# v2-Docker Projekt Journal

## Projektübersicht
Lizenzmanagement-System für Social Media Account-Erstellungssoftware mit Docker-basierter Architektur.

### Technische Anforderungen
- **Lokaler Betrieb**: Docker mit 4GB RAM und 40GB Speicher
- **Internet-Zugriff**: 
  - Admin Panel: https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com
  - API Server: https://api-software-undso.z5m7q9dk3ah2v1plx6ju.com
- **Datenbank**: PostgreSQL mit 2 Admin-Usern (rac00n, w@rh@mm3r)
- **Ziel**: PoC für spätere VPS-Migration

---

## Aktueller Stand (2025-06-07)

### ✅ Implementiert
1. **Docker-Infrastruktur**
   - docker-compose.yaml mit 4 Services (PostgreSQL, Admin Panel, License Server, Nginx)
   - Interne Bridge-Netzwerkkommunikation
   - Resource Limits konfiguriert (2 CPUs, 4GB RAM pro Service)
   - Nginx Reverse Proxy für SSL-Termination

2. **PostgreSQL Datenbank**
   - Tabellen: customers, licenses, sessions, audit_log, backup_history
   - UTF-8 Support mit deutscher Locale (de_DE.UTF-8)
   - Init-Script mit vollständigem Schema
   - Persistente Datenspeicherung

3. **Admin Panel (Vollständig)**
   - Flask-Anwendung mit Session-Management
   - Login-Funktionalität für 2 Admin-User (rac00n, w@rh@mm3r)
   - Dashboard mit Statistiken und Widgets
   - Lizenz-CRUD (Create, Read, Update, Delete)
   - Kunden-CRUD mit Lizenzzuordnung
   - Session-Tracking und -Verwaltung
   - Audit-Log für alle Aktionen
   - Export-Funktion (CSV/Excel)
   - Backup-System mit Verschlüsselung
   - UTF-8 Support für deutsche Umlaute
   - Suche und Filter mit Pagination

4. **Internet-Zugriff**
   - Nginx Reverse Proxy mit SSL-Termination
   - IONOS SSL-Zertifikate mit vollständiger Certificate Chain
   - Subdomain-Routing funktioniert (admin-panel-undso, api-software-undso)
   - DynDNS und Port-Forwarding konfiguriert
   - Feste IP-Adresse (192.168.178.88)

### ❌ Noch nicht implementiert
1. **License Server API**
   - Nur Platzhalter-Container vorhanden
   - Keine API-Endpunkte (/api/version, /api/validate, /api/heartbeat)
   - Keine Lizenzvalidierung
   - Kein aktives Session-Management

---

## Offene Aufgaben (Priorität)

### 🔴 Hoch (Basis-Funktionalität)
1. **License Server API implementieren**
   - `/api/version` - Versionscheck
   - `/api/validate` - Lizenzvalidierung
   - `/api/heartbeat` - Session-Management
2. **Reverse Proxy Setup** (Nginx/Traefik) für Subdomain-Routing
3. **SSL-Zertifikate** (Let's Encrypt) für beide Subdomains
4. **Session-Management** (nur eine aktive Session pro Lizenz)

### 🟡 Mittel (Erweiterte Features)
1. **Erweiterte Sicherheit**
   - Rate-Limiting für Login-Versuche (Brute-Force-Schutz)
   - 2-Faktor-Authentifizierung (2FA)
   - Session-Timeout konfigurierbar
   - IP-Whitelist für Admin-Zugriff
   - Passwort-Richtlinien (Komplexität, Ablauf)

2. **Lizenz-Verwaltung Erweiterungen**
   - Bulk-Import von Lizenzen (CSV/Excel Upload)
   - Lizenz-Templates für schnelle Erstellung
   - Lizenz-Verlängerung mit einem Klick
   - Lizenz-Historie (wer hatte welche Lizenz wann)
   - Lizenz-Gruppen/Pakete
   - Automatische Lizenzverlängerung

3. **Benachrichtigungen**
   - E-Mail bei ablaufenden Lizenzen (Struktur bereits vorbereitet)
   - Dashboard-Benachrichtigungen (Toast/Pop-ups)
   - Webhook-Support für externe Systeme
   - SMS-Benachrichtigungen
   - Slack/Teams Integration

4. **API für Automatisierung**
   - REST API für Admin-Funktionen
   - API-Keys für programmatischen Zugriff
   - Swagger/OpenAPI Dokumentation
   - Rate Limiting für API
   - Webhook Events

### 🟢 Niedrig (Nice-to-have)
1. **Benutzeroberfläche**
   - Dark Mode Toggle
   - Mobile-optimierte Ansicht (Responsive)
   - Mehrsprachigkeit (Deutsch/Englisch)
   - Anpassbare Dashboard-Widgets
   - Drag & Drop Dashboard
   - Keyboard Shortcuts

2. **Erweiterte Statistiken**
   - Grafische Auswertungen (Chart.js/D3.js)
   - Umsatz-Statistiken
   - Nutzungsstatistiken pro Kunde
   - Lizenz-Verlaufsdiagramme
   - Geografische Verteilung
   - Vorhersage-Analysen

3. **Weitere Features**
   - Rechnungserstellung
   - Mehrmandantenfähigkeit
   - Benutzerverwaltung (verschiedene Admin-Rollen)
   - Lizenz-Aktivierung per E-Mail
   - QR-Code für Lizenzschlüssel
   - Dokumentenverwaltung pro Kunde
   - JWT-Authentifizierung für API
   - Docker Resource-Optimierung
   - VPS-Migrationsdokumentation

---

## Bekannte Probleme
1. PostgreSQL Volume-Pfad wurde von absolutem Windows-Pfad auf Docker Volume geändert
2. Duplizierte .env Datei in templates/ Ordner
3. Credentials im Klartext in .env Dateien
4. Selbstsignierte SSL-Zertifikate verursachen Browser-Warnungen

---

## Nächste Schritte
1. UTF-8 Support implementieren
2. Reverse Proxy mit SSL einrichten
3. Admin Panel Funktionalität erweitern
4. License Server API entwickeln

---

## Änderungsprotokoll

### 2025-06-06 - Journal erstellt
- Initialer Projektstand dokumentiert
- Aufgabenliste priorisiert
- Technische Anforderungen festgehalten

### 2025-06-06 - UTF-8 Support implementiert
- Flask App Konfiguration für UTF-8 hinzugefügt (JSON_AS_ASCII=False)
- PostgreSQL Verbindung mit UTF-8 client_encoding
- HTML Forms mit accept-charset="UTF-8"
- Dockerfile mit deutschen Locale-Einstellungen (de_DE.UTF-8)
- PostgreSQL Container mit UTF-8 Initialisierung
- init.sql mit SET client_encoding = 'UTF8'

**Geänderte Dateien:**
- v2_adminpanel/app.py
- v2_adminpanel/templates/index.html
- v2_adminpanel/init.sql
- v2_adminpanel/Dockerfile
- v2/docker-compose.yaml

**Nächster Test:**
- Container neu bauen und starten
- Kundennamen mit Umlauten testen (z.B. "Müller GmbH", "Björn Schäfer")
- Email mit Umlauten testen

### 2025-06-06 - Lizenzübersicht implementiert
- Neue Route `/licenses` für Lizenzübersicht
- SQL-Query mit JOIN zwischen licenses und customers
- Status-Berechnung (aktiv, läuft bald ab, abgelaufen)
- Farbcodierung für verschiedene Status
- Navigation zwischen Lizenz erstellen und Übersicht

**Neue Features:**
- Anzeige aller Lizenzen mit Kundeninformationen
- Status-Anzeige basierend auf Ablaufdatum
- Unterscheidung zwischen Voll- und Testversion
- Responsive Tabelle mit Bootstrap
- Link von Dashboard zur Übersicht und zurück

**Geänderte/Neue Dateien:**
- v2_adminpanel/app.py (neue Route hinzugefügt)
- v2_adminpanel/templates/licenses.html (neu erstellt)
- v2_adminpanel/templates/index.html (Navigation ergänzt)

**Nächster Test:**
- Container neu starten
- Mehrere Lizenzen mit verschiedenen Ablaufdaten erstellen
- Lizenzübersicht unter /licenses aufrufen

### 2025-06-06 - Lizenz bearbeiten/löschen implementiert
- Neue Routen für Bearbeiten und Löschen von Lizenzen
- Bearbeitungsformular mit vorausgefüllten Werten
- Aktiv/Inaktiv-Status kann geändert werden
- Lösch-Bestätigung per JavaScript confirm()
- Kunde kann nicht geändert werden (nur Lizenzdetails)

**Neue Features:**
- `/license/edit/<id>` - Bearbeitungsformular
- `/license/delete/<id>` - Lizenz löschen (POST)
- Aktionen-Spalte in der Lizenzübersicht
- Buttons für Bearbeiten und Löschen
- Checkbox für Aktiv-Status

**Geänderte/Neue Dateien:**
- v2_adminpanel/app.py (edit_license und delete_license Routen)
- v2_adminpanel/templates/licenses.html (Aktionen-Spalte hinzugefügt)
- v2_adminpanel/templates/edit_license.html (neu erstellt)

**Sicherheit:**
- Login-Required für alle Aktionen
- POST-only für Löschvorgänge
- Bestätigungsdialog vor dem Löschen

### 2025-06-06 - Kundenverwaltung implementiert
- Komplette CRUD-Funktionalität für Kunden
- Übersicht zeigt Anzahl aktiver/gesamter Lizenzen pro Kunde
- Kunden können nur gelöscht werden, wenn sie keine Lizenzen haben
- Bearbeitungsseite zeigt alle Lizenzen des Kunden

**Neue Features:**
- `/customers` - Kundenübersicht mit Statistiken
- `/customer/edit/<id>` - Kunde bearbeiten (Name, E-Mail)
- `/customer/delete/<id>` - Kunde löschen (nur ohne Lizenzen)
- Navigation zwischen allen drei Hauptbereichen
- Anzeige der Kundenlizenzen beim Bearbeiten

**Geänderte/Neue Dateien:**
- v2_adminpanel/app.py (customers, edit_customer, delete_customer Routen)
- v2_adminpanel/templates/customers.html (neu erstellt)
- v2_adminpanel/templates/edit_customer.html (neu erstellt)
- v2_adminpanel/templates/index.html (Navigation erweitert)
- v2_adminpanel/templates/licenses.html (Navigation erweitert)

**Besonderheiten:**
- Lösch-Button ist deaktiviert, wenn Kunde Lizenzen hat
- Aktive Lizenzen werden separat gezählt (nicht abgelaufen + aktiv)
- UTF-8 Support für Kundennamen mit Umlauten

### 2025-06-06 - Dashboard mit Statistiken implementiert
- Übersichtliches Dashboard als neue Startseite
- Statistik-Karten mit wichtigen Kennzahlen
- Listen für bald ablaufende und zuletzt erstellte Lizenzen
- Routing angepasst: Dashboard (/) und Lizenz erstellen (/create)

**Neue Features:**
- Statistik-Karten: Kunden, Lizenzen gesamt, Aktive, Ablaufende
- Aufteilung nach Lizenztypen (Vollversion/Testversion)
- Aufteilung nach Status (Aktiv/Abgelaufen)
- Top 10 bald ablaufende Lizenzen mit Restlaufzeit
- Letzte 5 erstellte Lizenzen mit Status
- Hover-Effekt auf Statistik-Karten
- Einheitliche Navigation mit Dashboard-Link

**Geänderte/Neue Dateien:**
- v2_adminpanel/app.py (dashboard() komplett überarbeitet, create_license() Route)
- v2_adminpanel/templates/dashboard.html (neu erstellt)
- v2_adminpanel/templates/index.html (Navigation erweitert)
- v2_adminpanel/templates/licenses.html (Navigation angepasst)
- v2_adminpanel/templates/customers.html (Navigation angepasst)

**Dashboard-Inhalte:**
- 4 Hauptstatistiken als Karten
- Lizenztyp-Verteilung
- Status-Verteilung
- Warnung für bald ablaufende Lizenzen
- Übersicht der neuesten Aktivitäten

### 2025-06-06 - Suchfunktion implementiert
- Volltextsuche für Lizenzen und Kunden
- Case-insensitive Suche mit LIKE-Operator
- Suchergebnisse mit Hervorhebung des Suchbegriffs
- Suche zurücksetzen Button

**Neue Features:**
- **Lizenzsuche**: Sucht in Lizenzschlüssel, Kundenname und E-Mail
- **Kundensuche**: Sucht in Kundenname und E-Mail
- Suchformular mit autofocus für schnelle Eingabe
- Anzeige des aktiven Suchbegriffs
- Unterschiedliche Meldungen für leere Ergebnisse

**Geänderte Dateien:**
- v2_adminpanel/app.py (licenses() und customers() mit Suchlogik erweitert)
- v2_adminpanel/templates/licenses.html (Suchformular hinzugefügt)
- v2_adminpanel/templates/customers.html (Suchformular hinzugefügt)

**Technische Details:**
- GET-Parameter für Suche
- SQL LIKE mit LOWER() für Case-Insensitive Suche
- Wildcards (%) für Teilstring-Suche
- UTF-8 kompatibel für deutsche Umlaute

### 2025-06-06 - Filter und Pagination implementiert
- Erweiterte Filteroptionen für Lizenzübersicht
- Pagination für große Datenmengen (20 Einträge pro Seite)
- Filter bleiben bei Seitenwechsel erhalten

**Neue Features für Lizenzen:**
- **Filter nach Typ**: Alle, Vollversion, Testversion
- **Filter nach Status**: Alle, Aktiv, Läuft bald ab, Abgelaufen, Deaktiviert
- **Kombinierbar mit Suche**: Filter und Suche funktionieren zusammen
- **Pagination**: Navigation durch mehrere Seiten
- **Ergebnisanzeige**: Zeigt Anzahl gefilterter Ergebnisse

**Neue Features für Kunden:**
- **Pagination**: 20 Kunden pro Seite
- **Seitennavigation**: Erste, Letzte, Vor, Zurück
- **Kombiniert mit Suche**: Suchparameter bleiben erhalten

**Geänderte Dateien:**
- v2_adminpanel/app.py (licenses() und customers() mit Filter/Pagination erweitert)
- v2_adminpanel/templates/licenses.html (Filter-Formular und Pagination hinzugefügt)
- v2_adminpanel/templates/customers.html (Pagination hinzugefügt)

**Technische Details:**
- SQL WHERE-Klauseln für Filter
- LIMIT/OFFSET für Pagination
- URL-Parameter bleiben bei Navigation erhalten
- Responsive Bootstrap-Komponenten

### 2025-06-06 - Session-Tracking implementiert
- Neue Tabelle für Session-Verwaltung
- Anzeige aktiver und beendeter Sessions
- Manuelles Beenden von Sessions möglich
- Dashboard zeigt Anzahl aktiver Sessions

**Neue Features:**
- **Sessions-Tabelle**: Speichert Session-ID, IP, User-Agent, Zeitstempel
- **Aktive Sessions**: Zeigt alle laufenden Sessions mit Inaktivitätszeit
- **Session-Historie**: Letzte 24 Stunden beendeter Sessions
- **Session beenden**: Admins können Sessions manuell beenden
- **Farbcodierung**: Grün (aktiv), Gelb (>5 Min inaktiv), Rot (lange inaktiv)

**Geänderte/Neue Dateien:**
- v2_adminpanel/init.sql (sessions Tabelle hinzugefügt)
- v2_adminpanel/app.py (sessions() und end_session() Routen)
- v2_adminpanel/templates/sessions.html (neu erstellt)
- v2_adminpanel/templates/dashboard.html (Session-Statistik)
- Alle Templates (Session-Navigation hinzugefügt)

**Technische Details:**
- Heartbeat-basiertes Tracking (last_heartbeat)
- Automatische Inaktivitätsberechnung
- Session-Dauer Berechnung
- Responsive Tabellen mit Bootstrap

**Hinweis:**
Die Session-Daten werden erst gefüllt, wenn der License Server API implementiert ist und Clients sich verbinden.

### 2025-06-06 - Export-Funktion implementiert
- CSV und Excel Export für Lizenzen und Kunden
- Formatierte Ausgabe mit deutschen Datumsformaten
- UTF-8 Unterstützung für Sonderzeichen

**Neue Features:**
- **Lizenz-Export**: Alle Lizenzen mit Kundeninformationen
- **Kunden-Export**: Alle Kunden mit Lizenzstatistiken
- **Format-Optionen**: Excel (.xlsx) und CSV (.csv)
- **Deutsche Formatierung**: Datum als dd.mm.yyyy, Status auf Deutsch
- **UTF-8 Export**: Korrekte Kodierung für Umlaute
- **Export-Buttons**: Dropdown-Menüs in Lizenz- und Kundenübersicht

**Geänderte Dateien:**
- v2_adminpanel/app.py (export_licenses() und export_customers() Routen)
- v2_adminpanel/requirements.txt (pandas und openpyxl hinzugefügt)
- v2_adminpanel/templates/licenses.html (Export-Dropdown hinzugefügt)
- v2_adminpanel/templates/customers.html (Export-Dropdown hinzugefügt)

**Technische Details:**
- Pandas für Datenverarbeitung
- OpenPyXL für Excel-Export
- CSV mit Semikolon-Trennung für deutsche Excel-Kompatibilität
- Automatische Spaltenbreite in Excel
- BOM für UTF-8 CSV (Excel-Kompatibilität)

### 2025-06-06 - Audit-Log implementiert
- Vollständiges Änderungsprotokoll für alle Aktionen
- Filterbare Übersicht mit Pagination
- Detaillierte Anzeige von Änderungen

**Neue Features:**
- **Audit-Log-Tabelle**: Speichert alle Änderungen mit Zeitstempel, Benutzer, IP
- **Protokollierte Aktionen**: CREATE, UPDATE, DELETE, LOGIN, LOGOUT, EXPORT
- **JSON-Speicherung**: Alte und neue Werte als JSONB für flexible Abfragen
- **Filter-Optionen**: Nach Benutzer, Aktion und Entität
- **Detail-Anzeige**: Aufklappbare Änderungsdetails
- **Navigation**: Audit-Link in allen Templates

**Geänderte/Neue Dateien:**
- v2_adminpanel/init.sql (audit_log Tabelle mit Indizes)
- v2_adminpanel/app.py (log_audit() Funktion und audit_log() Route)
- v2_adminpanel/templates/audit_log.html (neu erstellt)
- Alle Templates (Audit-Navigation hinzugefügt)

**Technische Details:**
- JSONB für strukturierte Datenspeicherung
- Performance-Indizes auf timestamp, username und entity
- Farbcodierung für verschiedene Aktionen
- 50 Einträge pro Seite mit Pagination
- IP-Adresse und User-Agent Tracking

### 2025-06-06 - PostgreSQL UTF-8 Locale konfiguriert
- Eigenes PostgreSQL Dockerfile für deutsche Locale
- Sicherstellung der UTF-8 Unterstützung auf Datenbankebene

**Neue Features:**
- **PostgreSQL Dockerfile**: Installiert deutsche Locale (de_DE.UTF-8)
- **Locale-Umgebungsvariablen**: LANG, LANGUAGE, LC_ALL gesetzt
- **Docker Compose Update**: Verwendet jetzt eigenes PostgreSQL-Image

**Neue Dateien:**
- v2_postgres/Dockerfile (neu erstellt)

**Geänderte Dateien:**
- v2/docker-compose.yaml (postgres Service nutzt jetzt build statt image)

**Technische Details:**
- Basis-Image: postgres:14
- Locale-Installation über apt-get
- locale-gen für de_DE.UTF-8
- Vollständige UTF-8 Unterstützung für deutsche Sonderzeichen

### 2025-06-07 - Backup-Funktionalität implementiert
- Verschlüsselte Backups mit manueller und automatischer Ausführung
- Backup-Historie mit Download und Wiederherstellung
- Dashboard-Integration für Backup-Status

**Neue Features:**
- **Backup-Erstellung**: Manuell und automatisch (täglich 3:00 Uhr)
- **Verschlüsselung**: AES-256 mit Fernet, Key aus ENV oder automatisch generiert
- **Komprimierung**: GZIP-Komprimierung vor Verschlüsselung
- **Backup-Historie**: Vollständige Übersicht aller Backups
- **Wiederherstellung**: Mit optionalem Verschlüsselungs-Passwort
- **Download-Funktion**: Backups können heruntergeladen werden
- **Dashboard-Widget**: Zeigt letztes Backup-Status
- **E-Mail-Vorbereitung**: Struktur für Benachrichtigungen (deaktiviert)

**Neue/Geänderte Dateien:**
- v2_adminpanel/init.sql (backup_history Tabelle hinzugefügt)
- v2_adminpanel/requirements.txt (cryptography, apscheduler hinzugefügt)
- v2_adminpanel/app.py (Backup-Funktionen und Routen)
- v2_adminpanel/templates/backups.html (neu erstellt)
- v2_adminpanel/templates/dashboard.html (Backup-Status-Widget)
- v2_adminpanel/Dockerfile (PostgreSQL-Client installiert)
- v2/.env (EMAIL_ENABLED und BACKUP_ENCRYPTION_KEY)
- Alle Templates (Backup-Navigation hinzugefügt)

**Technische Details:**
- Speicherort: C:\Users\Administrator\Documents\GitHub\v2-Docker\backups\
- Dateiformat: backup_v2docker_YYYYMMDD_HHMMSS_encrypted.sql.gz.enc
- APScheduler für automatische Backups
- pg_dump/psql für Datenbank-Operationen
- Audit-Log für alle Backup-Aktionen
- Sicherheitsabfrage bei Wiederherstellung

### 2025-06-07 - HTTPS/SSL und Internet-Zugriff implementiert
- Nginx Reverse Proxy für externe Erreichbarkeit eingerichtet
- SSL-Zertifikate von IONOS mit vollständiger Certificate Chain integriert
- Netzwerkkonfiguration für feste IP-Adresse
- DynDNS und Port-Forwarding konfiguriert

**Neue Features:**
- **Nginx Reverse Proxy**: Leitet HTTPS-Anfragen an Container weiter
- **SSL-Zertifikate**: Wildcard-Zertifikat von IONOS für *.z5m7q9dk3ah2v1plx6ju.com
- **Certificate Chain**: Server-, Intermediate- und Root-Zertifikate kombiniert
- **Subdomain-Routing**: admin-panel-undso und api-software-undso
- **Port-Forwarding**: FRITZ!Box 443 → 192.168.178.88
- **Feste IP**: Windows-PC auf 192.168.178.88 konfiguriert

**Neue/Geänderte Dateien:**
- v2_nginx/nginx.conf (Reverse Proxy Konfiguration)
- v2_nginx/Dockerfile (Nginx Container mit SSL)
- v2_nginx/ssl/fullchain.pem (Certificate Chain)
- v2_nginx/ssl/privkey.pem (Private Key)
- v2/docker-compose.yaml (nginx Service hinzugefügt)
- set-static-ip.ps1 (PowerShell Script für feste IP)
- reset-to-dhcp.ps1 (PowerShell Script für DHCP)

**Technische Details:**
- SSL-Termination am Nginx Reverse Proxy
- Backend-Kommunikation über Docker-internes Netzwerk
- Admin-Panel nur noch über Nginx erreichbar (Port 443 nicht mehr exposed)
- License-Server behält externen Port 8443 für direkte API-Zugriffe
- Intermediate Certificates aus ZIP extrahiert und korrekt verkettet

**Zugangsdaten:**
- Admin-Panel: https://admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com
- Benutzer 1: rac00n / 1248163264
- Benutzer 2: w@rh@mm3r / Warhammer123!

**Status:**
- ✅ Admin-Panel extern erreichbar ohne SSL-Warnungen
- ✅ Reverse Proxy funktioniert
- ✅ SSL-Zertifikate korrekt konfiguriert
- ✅ Netzwerk-Setup abgeschlossen

### 2025-06-07 - Projekt-Cleanup durchgeführt
- Redundante und überflüssige Dateien entfernt
- Projektstruktur verbessert und organisiert

**Durchgeführte Änderungen:**
1. **Entfernte Dateien:**
   - v2_adminpanel/templates/.env (Duplikat der Haupt-.env)
   - v2_postgreSQL/ (leeres Verzeichnis)
   - SSL-Zertifikate aus Root-Verzeichnis (7 Dateien)
   - Ungenutzer `json` Import aus app.py

2. **Organisatorische Verbesserungen:**
   - PowerShell-Scripts in neuen `scripts/` Ordner verschoben
   - SSL-Zertifikate nur noch in v2_nginx/ssl/
   - Keine Konfigurationsdateien mehr in Template-Verzeichnissen

**Technische Details:**
- Docker-Container wurden gestoppt und nach Cleanup neu gestartet
- Alle Services laufen wieder normal
- Keine funktionalen Änderungen, nur Struktur-Verbesserungen

**Ergebnis:**
- Verbesserte Projektstruktur
- Erhöhte Sicherheit (keine SSL-Zertifikate im Root)
- Klarere Dateiorganisation

### 2025-06-07 - SSL "Nicht sicher" Problem behoben
- Chrome-Warnung trotz gültigem Zertifikat analysiert und behoben
- Ursache: Selbstsigniertes Zertifikat in der Admin Panel Flask-App

**Durchgeführte Änderungen:**
1. **Admin Panel Konfiguration (app.py):**
   - Von HTTPS mit selbstsigniertem Zertifikat auf HTTP Port 5000 umgestellt
   - `ssl_context='adhoc'` entfernt
   - Flask läuft jetzt auf `0.0.0.0:5000` statt HTTPS

2. **Dockerfile Anpassung (v2_adminpanel/Dockerfile):**
   - EXPOSE Port von 443 auf 5000 geändert
   - Container exponiert jetzt HTTP statt HTTPS

3. **Nginx Konfiguration (nginx.conf):**
   - proxy_pass von `https://admin-panel:443` auf `http://admin-panel:5000` geändert
   - `proxy_ssl_verify off` entfernt (nicht mehr benötigt)
   - Sicherheits-Header für beide Domains hinzugefügt:
     - Strict-Transport-Security (HSTS) - erzwingt HTTPS für 1 Jahr
     - X-Content-Type-Options - verhindert MIME-Type Sniffing
     - X-Frame-Options - Schutz vor Clickjacking
     - X-XSS-Protection - aktiviert XSS-Filter
     - Referrer-Policy - kontrolliert Referrer-Informationen

**Technische Details:**
- Externer Traffic nutzt weiterhin HTTPS mit gültigen IONOS-Zertifikaten
- Interne Kommunikation zwischen Nginx und Admin Panel läuft über HTTP (sicher im Docker-Netzwerk)
- Kein selbstsigniertes Zertifikat mehr in der Zertifikatskette
- SSL-Termination erfolgt ausschließlich am Nginx Reverse Proxy

**Docker Neustart:**
- Container gestoppt (`docker-compose down`)
- Images neu gebaut (`docker-compose build`)
- Container neu gestartet (`docker-compose up -d`)
- Alle Services laufen normal

**Ergebnis:**
- ✅ "Nicht sicher" Warnung in Chrome behoben
- ✅ Saubere SSL-Konfiguration ohne Mixed Content
- ✅ Verbesserte Sicherheits-Header implementiert
- ✅ Admin Panel zeigt jetzt grünes Schloss-Symbol

### 2025-06-07 - Sicherheitslücke geschlossen: License Server Port
- Direkter Zugriff auf License Server Port 8443 entfernt
- Sicherheitsanalyse der exponierten Ports durchgeführt

**Identifiziertes Problem:**
- License Server war direkt auf Port 8443 von außen erreichbar
- Umging damit die Nginx-Sicherheitsschicht und Security Headers
- Besonders kritisch, da nur Platzhalter ohne echte Sicherheit

**Durchgeführte Änderung:**
- Port-Mapping für License Server in docker-compose.yaml entfernt
- Service ist jetzt nur noch über Nginx Reverse Proxy erreichbar
- Gleiche Sicherheitskonfiguration wie Admin Panel

**Aktuelle Port-Exposition:**
- ✅ Nginx: Port 80/443 (benötigt für externen Zugriff)
- ✅ PostgreSQL: Keine Ports exponiert (gut)
- ✅ Admin Panel: Nur über Nginx erreichbar
- ✅ License Server: Nur über Nginx erreichbar (vorher direkt auf 8443)

**Weitere identifizierte Sicherheitsthemen:**
1. Credentials im Klartext in .env Datei
2. SSL-Zertifikate im Repository gespeichert
3. License Server noch nicht implementiert

**Empfehlung:** Docker-Container neu starten für Änderungsübernahme

### 2025-06-07 - License Server Port 8443 wieder aktiviert
- Port 8443 für direkten Zugriff auf License Server wieder geöffnet
- Notwendig für Client-Software Lizenzprüfung

**Begründung:**
- Client-Software benötigt direkten Zugriff für Lizenzprüfung
- Umgehung von möglichen Firewall-Blockaden auf Port 443
- Weniger Latenz ohne Nginx-Proxy
- Flexibilität für verschiedene Client-Implementierungen

**Konfiguration:**
- License Server erreichbar über:
  - Direkt: Port 8443 (für Client-Software)
  - Via Nginx: https://api-software-undso.z5m7q9dk3ah2v1plx6ju.com (für Browser/Tests)

**Sicherheitshinweis:**
- Port 8443 ist wieder direkt exponiert
- License Server muss vor Produktivbetrieb implementiert werden mit:
  - Eigener SSL-Konfiguration
  - API-Key Authentifizierung
  - Rate Limiting
  - Input-Validierung

**Status:**
- Port-Mapping in docker-compose.yaml wiederhergestellt
- Änderung erfordert Docker-Neustart

### 2025-06-07 - Rate-Limiting und Brute-Force-Schutz implementiert
- Umfassender Schutz vor Login-Angriffen mit IP-Sperre
- Dashboard-Integration für Sicherheitsüberwachung

**Implementierte Features:**
1. **Rate-Limiting System:**
   - 5 Login-Versuche erlaubt, danach 24h IP-Sperre
   - Progressive Fehlermeldungen (zufällig aus 5 lustigen Varianten)
   - CAPTCHA nach 2 Fehlversuchen (Google reCAPTCHA v2 vorbereitet)
   - E-Mail-Benachrichtigung bei Sperrung (vorbereitet, deaktiviert für PoC)

2. **Timing-Attack Schutz:**
   - Mindestens 1 Sekunde Antwortzeit bei allen Login-Versuchen
   - Gleiche Antwortzeit bei richtigem/falschem Username
   - Verhindert Username-Enumeration

3. **Lustige Fehlermeldungen (zufällig):**
   - "NOPE!"
   - "ACCESS DENIED, TRY HARDER"
   - "WRONG! 🚫"
   - "COMPUTER SAYS NO"
   - "YOU FAILED"

4. **Dashboard-Sicherheitswidget:**
   - Sicherheitslevel-Anzeige (NORMAL/ERHÖHT/KRITISCH)
   - Anzahl gesperrter IPs
   - Fehlversuche heute
   - Letzte 5 Sicherheitsereignisse mit Details

5. **IP-Verwaltung:**
   - Übersicht aller gesperrten IPs
   - Manuelles Entsperren möglich
   - Login-Versuche zurücksetzen
   - Detaillierte Informationen pro IP

6. **Audit-Log Erweiterungen:**
   - LOGIN_SUCCESS - Erfolgreiche Anmeldung
   - LOGIN_FAILED - Fehlgeschlagener Versuch
   - LOGIN_BLOCKED - IP wurde gesperrt
   - UNBLOCK_IP - IP manuell entsperrt
   - CLEAR_ATTEMPTS - Versuche zurückgesetzt

**Neue/Geänderte Dateien:**
- v2_adminpanel/init.sql (login_attempts Tabelle)
- v2_adminpanel/app.py (Rate-Limiting Logik, neue Routen)
- v2_adminpanel/templates/login.html (Fehlermeldungs-Styling, CAPTCHA)
- v2_adminpanel/templates/dashboard.html (Sicherheitswidget)
- v2_adminpanel/templates/blocked_ips.html (neu - IP-Verwaltung)

**Technische Details:**
- IP-Ermittlung berücksichtigt Proxy-Header (X-Forwarded-For)
- Fehlermeldungen mit Animation (shake-effect)
- Farbcodierung: Rot für Fehler, Lila für Sperre, Orange für CAPTCHA
- Automatische Bereinigung alter Einträge möglich

**Sicherheitsverbesserungen:**
- Schutz vor Brute-Force-Angriffen
- Timing-Attack-Schutz implementiert
- IP-basierte Sperrung für 24 Stunden
- Audit-Trail für alle Sicherheitsereignisse

**Hinweis für Produktion:**
- CAPTCHA-Keys müssen in .env konfiguriert werden
- E-Mail-Server für Benachrichtigungen einrichten
- Rate-Limits können über Konstanten angepasst werden

### 2025-06-07 - Session-Timeout mit Live-Timer implementiert
- 5 Minuten Inaktivitäts-Timeout mit visueller Countdown-Anzeige
- Automatische Session-Verlängerung bei Benutzeraktivität

**Implementierte Features:**
1. **Session-Timeout Backend:**
   - Flask Session-Timeout auf 5 Minuten konfiguriert
   - Heartbeat-Endpoint für Keep-Alive
   - Automatisches Session-Update bei jeder Aktion

2. **Live-Timer in der Navbar:**
   - Countdown von 5:00 bis 0:00
   - Position: Zwischen Logo und Username
   - Farbwechsel nach verbleibender Zeit:
     - Grün: > 2 Minuten
     - Gelb: 1-2 Minuten
     - Rot: < 1 Minute
     - Blinkend: < 30 Sekunden

3. **Benutzerinteraktion:**
   - Timer wird bei jeder Aktivität zurückgesetzt
   - Tracking von: Klicks, Tastatureingaben, Mausbewegungen
   - Automatischer Heartbeat bei Aktivität
   - Warnung bei < 1 Minute mit "Session verlängern" Button

4. **Base-Template System:**
   - Neue base.html als Basis für alle Admin-Seiten
   - Alle Templates (außer login.html) nutzen jetzt base.html
   - Einheitliches Layout und Timer auf allen Seiten

**Neue/Geänderte Dateien:**
- v2_adminpanel/app.py (Session-Konfiguration, Heartbeat-Endpoint)
- v2_adminpanel/templates/base.html (neu - Base-Template mit Timer)
- Alle anderen Templates aktualisiert für Template-Vererbung

**Technische Details:**
- JavaScript-basierter Countdown-Timer
- AJAX-Heartbeat alle 5 Sekunden bei Aktivität
- LocalStorage für Tab-Synchronisation möglich
- Automatischer Logout bei 0:00
- Fetch-Interceptor für automatische Session-Verlängerung

**Sicherheitsverbesserung:**
- Automatischer Logout nach 5 Minuten Inaktivität
- Verhindert vergessene Sessions
- Visuelles Feedback für Session-Status

### 2025-06-07 - Session-Timeout Bug behoben
- Problem: Session-Timeout funktionierte nicht korrekt - Session blieb länger als 5 Minuten aktiv
- Ursache: login_required Decorator aktualisierte last_activity bei JEDEM Request

**Durchgeführte Änderungen:**
1. **login_required Decorator (app.py):**
   - Prüft jetzt ob Session abgelaufen ist (5 Minuten seit last_activity)
   - Aktualisiert last_activity NICHT mehr automatisch
   - Führt AUTO_LOGOUT mit Audit-Log bei Timeout durch
   - Speichert Username vor session.clear() für korrektes Logging

2. **Heartbeat-Endpoint (app.py):**
   - Geändert zu POST-only Endpoint
   - Aktualisiert explizit last_activity wenn aufgerufen
   - Wird nur bei aktiver Benutzerinteraktion aufgerufen

3. **Frontend Timer (base.html):**
   - Heartbeat wird als POST Request gesendet
   - trackActivity() ruft extendSession() ohne vorheriges resetTimer() auf
   - Timer wird erst nach erfolgreichem Heartbeat zurückgesetzt
   - AJAX Interceptor ignoriert Heartbeat-Requests

4. **Audit-Log Erweiterung:**
   - Neue Aktion AUTO_LOGOUT hinzugefügt
   - Orange Farbcodierung (#fd7e14)
   - Zeigt Grund des Timeouts im Audit-Log

**Ergebnis:**
- ✅ Session läuft nach exakt 5 Minuten Inaktivität ab
- ✅ Benutzeraktivität verlängert Session korrekt
- ✅ AUTO_LOGOUT wird im Audit-Log protokolliert
- ✅ Visueller Timer zeigt verbleibende Zeit

### 2025-06-07 - Session-Timeout weitere Verbesserungen
- Zusätzliche Fixes nach Test-Feedback implementiert

**Weitere durchgeführte Änderungen:**
1. **Fehlender Import behoben:**
   - `flash` zu Flask-Imports hinzugefügt für Timeout-Warnmeldungen

2. **Session-Cookie-Konfiguration erweitert (app.py):**
   - SESSION_COOKIE_HTTPONLY = True (Sicherheit gegen XSS)
   - SESSION_COOKIE_SECURE = False (intern HTTP, extern HTTPS via Nginx)
   - SESSION_COOKIE_SAMESITE = 'Lax' (CSRF-Schutz)
   - SESSION_COOKIE_NAME = 'admin_session' (eindeutiger Name)
   - SESSION_REFRESH_EACH_REQUEST = False (verhindert automatische Verlängerung)

3. **Session-Handling verbessert:**
   - Entfernt: session.permanent = True aus login_required decorator
   - Hinzugefügt: session.modified = True im Heartbeat für explizites Speichern
   - Debug-Logging für Session-Timeout-Prüfung hinzugefügt

4. **Nginx-Konfiguration:**
   - Bereits korrekt konfiguriert für Heartbeat-Weiterleitung
   - Proxy-Headers für korrekte IP-Weitergabe

**Technische Details:**
- Flask-Session mit Filesystem-Backend nutzt jetzt korrekte Cookie-Einstellungen
- Session-Cookie wird nicht mehr automatisch bei jedem Request verlängert
- Explizite Session-Modifikation nur bei Heartbeat-Requests
- Debug-Logs zeigen Zeit seit letzter Aktivität für Troubleshooting

**Status:**
- ✅ Session-Timeout-Mechanismus vollständig implementiert
- ✅ Debug-Logging für Session-Überwachung aktiv
- ✅ Cookie-Sicherheitseinstellungen optimiert

### 2025-06-07 - CAPTCHA Backend-Validierung implementiert
- Google reCAPTCHA v2 Backend-Verifizierung hinzugefügt

**Implementierte Features:**
1. **verify_recaptcha() Funktion (app.py):**
   - Validiert CAPTCHA-Response mit Google API
   - Fallback: Wenn RECAPTCHA_SECRET_KEY nicht konfiguriert, wird CAPTCHA übersprungen (für PoC)
   - Timeout von 5 Sekunden für API-Request
   - Error-Handling für Netzwerkfehler
   - Logging für Debugging und Fehleranalyse

2. **Login-Route Erweiterungen:**
   - CAPTCHA wird nach 2 Fehlversuchen angezeigt
   - Prüfung ob CAPTCHA-Response vorhanden
   - Validierung der CAPTCHA-Response gegen Google API
   - Unterschiedliche Fehlermeldungen für fehlende/ungültige CAPTCHA
   - Site Key wird aus Environment-Variable an Template übergeben

3. **Environment-Konfiguration (.env):**
   - RECAPTCHA_SITE_KEY (für Frontend)
   - RECAPTCHA_SECRET_KEY (für Backend-Validierung)
   - Beide auskommentiert für PoC-Phase

4. **Dependencies:**
   - requests Library zu requirements.txt hinzugefügt

**Sicherheitsaspekte:**
- CAPTCHA verhindert automatisierte Brute-Force-Angriffe
- Timing-Attack-Schutz bleibt auch bei CAPTCHA-Prüfung aktiv
- Bei Netzwerkfehlern wird CAPTCHA als bestanden gewertet (Verfügbarkeit vor Sicherheit)
- Secret Key wird niemals im Frontend exponiert

**Verwendung:**
1. Google reCAPTCHA v2 Keys erstellen: https://www.google.com/recaptcha/admin
2. Keys in .env eintragen:
   ```
   RECAPTCHA_SITE_KEY=your-site-key
   RECAPTCHA_SECRET_KEY=your-secret-key
   ```
3. Container neu starten

**Status:**
- ✅ CAPTCHA-Frontend bereits vorhanden (login.html)
- ✅ Backend-Validierung vollständig implementiert
- ✅ Fallback für PoC-Betrieb ohne Google-Keys
- ✅ Integration in Rate-Limiting-System
- ⚠️ CAPTCHA-Keys noch nicht konfiguriert (für PoC deaktiviert)

**Anleitung für Google reCAPTCHA Keys:**

1. **Registrierung bei Google reCAPTCHA:**
   - Gehe zu: https://www.google.com/recaptcha/admin/create
   - Melde dich mit Google-Konto an
   - Label eingeben: "v2-Docker Admin Panel"
   - Typ wählen: "reCAPTCHA v2" → "Ich bin kein Roboter"-Kästchen
   - Domains hinzufügen:
     ```
     admin-panel-undso.z5m7q9dk3ah2v1plx6ju.com
     localhost
     ```
   - Nutzungsbedingungen akzeptieren
   - Senden klicken

2. **Keys erhalten:**
   - Site Key (öffentlich für Frontend)
   - Secret Key (geheim für Backend-Validierung)

3. **Keys in .env eintragen:**
   ```bash
   RECAPTCHA_SITE_KEY=6Ld...
   RECAPTCHA_SECRET_KEY=6Ld...
   ```

4. **Container neu starten:**
   ```bash
   docker-compose down
   docker-compose up -d
   ```

**Kosten:**
- Kostenlos bis 1 Million Anfragen pro Monat
- Danach: $1.00 pro 1000 zusätzliche Anfragen
- Für dieses Projekt reicht die kostenlose Version vollkommen aus

**Test-Keys für Entwicklung:**
- Site Key: `6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI`
- Secret Key: `6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe`
- ⚠️ Diese Keys nur für lokale Tests verwenden, niemals produktiv!

**Aktueller Status:**
- Code ist vollständig implementiert und getestet
- CAPTCHA wird nach 2 Fehlversuchen angezeigt
- Ohne konfigurierte Keys wird CAPTCHA-Prüfung übersprungen
- Für Produktion müssen nur die Keys in .env eingetragen werden

### 2025-06-07 - License Key Generator implementiert
- Automatische Generierung von Lizenzschlüsseln mit definiertem Format

**Implementiertes Format:**
`AF-YYYYMMFT-XXXX-YYYY-ZZZZ`
- **AF** = Account Factory (feste Produktkennung)
- **YYYY** = Jahr (z.B. 2025)
- **MM** = Monat (z.B. 06)
- **FT** = Lizenztyp (F=Fullversion, T=Testversion)
- **XXXX-YYYY-ZZZZ** = Zufällige alphanumerische Zeichen (ohne verwirrende wie 0/O, 1/I/l)

**Beispiele:**
- Vollversion: `AF-202506F-A7K9-M3P2-X8R4`
- Testversion: `AF-202512T-B2N5-K8L3-Q9W7`

**Implementierte Features:**

1. **Backend-Funktionen (app.py):**
   - `generate_license_key()` - Generiert Keys mit kryptografisch sicherem Zufallsgenerator
   - `validate_license_key()` - Validiert das Key-Format mit Regex
   - Verwendet `secrets` statt `random` für Sicherheit
   - Erlaubte Zeichen: ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (ohne verwirrende)

2. **API-Endpoint:**
   - POST `/api/generate-license-key` - JSON API für Key-Generierung
   - Prüft auf Duplikate in der Datenbank (max. 10 Versuche)
   - Audit-Log-Eintrag bei jeder Generierung
   - Login-Required geschützt

3. **Frontend-Verbesserungen (index.html):**
   - Generate-Button neben License Key Input
   - Placeholder und Pattern-Attribut für Format-Hinweis
   - Auto-Uppercase bei manueller Eingabe
   - Visuelles Feedback bei erfolgreicher Generierung
   - Format-Hinweis unter dem Eingabefeld

4. **JavaScript-Features:**
   - AJAX-basierte Key-Generierung ohne Seiten-Reload
   - Automatische Prüfung bei Lizenztyp-Änderung
   - Ladeindikator während der Generierung
   - Fehlerbehandlung mit Benutzer-Feedback
   - Standard-Datum-Einstellungen (heute + 1 Jahr)

5. **Validierung:**
   - Server-seitige Format-Validierung beim Speichern
   - Flash-Message bei ungültigem Format
   - Automatische Großschreibung des Keys
   - Pattern-Validierung im HTML-Formular

6. **Weitere Fixes:**
   - Form Action von "/" auf "/create" korrigiert
   - Flash-Messages mit Bootstrap Toasts implementiert
   - GENERATE_KEY Aktion zum Audit-Log hinzugefügt (Farbe: #20c997)

**Technische Details:**
- Keine vorhersagbaren Muster durch `secrets.choice()`
- Datum im Key zeigt Erstellungszeitpunkt
- Lizenztyp direkt im Key erkennbar
- Kollisionsprüfung gegen Datenbank

**Status:**
- ✅ Backend-Generierung vollständig implementiert
- ✅ Frontend mit Generate-Button und JavaScript
- ✅ Validierung und Fehlerbehandlung
- ✅ Audit-Log-Integration
- ✅ Form-Action-Bug behoben

### 2025-06-07 - Batch-Lizenzgenerierung implementiert
- Mehrere Lizenzen auf einmal für einen Kunden erstellen

**Implementierte Features:**

1. **Batch-Formular (/batch):**
   - Kunde und E-Mail eingeben
   - Anzahl der Lizenzen (1-100)
   - Lizenztyp (Vollversion/Testversion)
   - Gültigkeitszeitraum für alle Lizenzen
   - Vorschau-Modal zeigt Key-Format
   - Standard-Datum-Einstellungen (heute + 1 Jahr)

2. **Backend-Verarbeitung:**
   - Route `/batch` für GET (Formular) und POST (Generierung)
   - Generiert die angegebene Anzahl eindeutiger Keys
   - Speichert alle in einer Transaktion
   - Kunde wird automatisch angelegt (falls nicht vorhanden)
   - ON CONFLICT für existierende Kunden
   - Audit-Log-Eintrag mit CREATE_BATCH Aktion

3. **Ergebnis-Seite:**
   - Zeigt alle generierten Lizenzen in Tabellenform
   - Kundeninformationen und Gültigkeitszeitraum
   - Einzelne Keys können kopiert werden (📋 Button)
   - Alle Keys auf einmal kopieren
   - Druckfunktion für physische Ausgabe
   - Link zur Lizenzübersicht mit Kundenfilter

4. **Export-Funktionalität:**
   - Route `/batch/export` für CSV-Download
   - Speichert Batch-Daten in Session für Export
   - CSV mit UTF-8 BOM für Excel-Kompatibilität
   - Enthält Kundeninfo, Generierungsdatum und alle Keys
   - Format: Nr;Lizenzschlüssel;Typ
   - Dateiname: batch_licenses_KUNDE_TIMESTAMP.csv

5. **Integration:**
   - Batch-Button in Navigation (Dashboard, Einzellizenz-Seite)
   - CREATE_BATCH Aktion im Audit-Log (Farbe: #6610f2)
   - Session-basierte Export-Daten
   - Flash-Messages für Feedback

**Sicherheit:**
- Limit von 100 Lizenzen pro Batch
- Login-Required für alle Routen
- Transaktionale Datenbank-Operationen
- Validierung der Eingaben

**Beispiel-Workflow:**
1. Admin geht zu `/batch`
2. Gibt Kunde "Firma GmbH", Anzahl "25", Typ "Vollversion" ein
3. System generiert 25 eindeutige Keys
4. Ergebnis-Seite zeigt alle Keys
5. Admin kann CSV exportieren oder Keys kopieren
6. Kunde erhält die Lizenzen

**Status:**
- ✅ Batch-Formular vollständig implementiert
- ✅ Backend-Generierung mit Transaktionen
- ✅ Export als CSV
- ✅ Copy-to-Clipboard Funktionalität
- ✅ Audit-Log-Integration
- ✅ Navigation aktualisiert

## 2025-01-06: Implementierung Searchable Dropdown für Kundenauswahl

**Problem:**
- Bei der Lizenzerstellung wurde immer ein neuer Kunde angelegt
- Keine Möglichkeit, Lizenzen für bestehende Kunden zu erstellen
- Bei vielen Kunden wäre ein normales Dropdown unübersichtlich

**Lösung:**
1. **Select2 Library** für searchable Dropdown integriert
2. **API-Endpoint `/api/customers`** für die Kundensuche erstellt
3. **Frontend angepasst:**
   - Searchable Dropdown mit Live-Suche
   - Option "Neuer Kunde" im Dropdown
   - Eingabefelder erscheinen nur bei "Neuer Kunde"
4. **Backend-Logik verbessert:**
   - Prüfung ob neuer oder bestehender Kunde
   - E-Mail-Duplikatsprüfung vor Kundenerstellung
   - Separate Audit-Logs für Kunde und Lizenz
5. **Datenbank:**
   - UNIQUE Constraint auf E-Mail-Spalte hinzugefügt

**Änderungen:**
- `app.py`: Neuer API-Endpoint `/api/customers`, angepasste Routes `/create` und `/batch`
- `base.html`: Select2 CSS und JS eingebunden
- `index.html`: Kundenauswahl mit Select2 implementiert
- `batch_form.html`: Kundenauswahl mit Select2 implementiert
- `init.sql`: UNIQUE Constraint für E-Mail

**Status:**
- ✅ API-Endpoint funktioniert mit Pagination
- ✅ Select2 Dropdown mit Suchfunktion
- ✅ Neue/bestehende Kunden können ausgewählt werden
- ✅ E-Mail-Duplikate werden verhindert
- ✅ Sowohl Einzellizenz als auch Batch unterstützt

## 2025-01-06: Automatische Ablaufdatum-Berechnung

**Problem:**
- Manuelles Eingeben von Start- und Enddatum war umständlich
- Fehleranfällig bei der Datumseingabe
- Nicht intuitiv für Standard-Laufzeiten

**Lösung:**
1. **Frontend-Änderungen:**
   - Startdatum + Laufzeit (Zahl) + Einheit (Tage/Monate/Jahre)
   - Ablaufdatum wird automatisch berechnet und angezeigt (read-only)
   - Standard: 1 Jahr Laufzeit voreingestellt
2. **Backend-Validierung:**
   - Server-seitige Berechnung zur Sicherheit
   - Verwendung von `python-dateutil` für korrekte Monats-/Jahresberechnungen
3. **Benutzerfreundlichkeit:**
   - Sofortige Neuberechnung bei Änderungen
   - Visuelle Hervorhebung des berechneten Datums

**Änderungen:**
- `index.html`: Laufzeit-Eingabe statt Ablaufdatum
- `batch_form.html`: Laufzeit-Eingabe statt Ablaufdatum
- `app.py`: Datum-Berechnung in `/create` und `/batch` Routes
- `requirements.txt`: `python-dateutil` hinzugefügt

**Status:**
- ✅ Automatische Berechnung funktioniert
- ✅ Frontend zeigt berechnetes Datum sofort an
- ✅ Backend validiert die Berechnung
- ✅ Standardwert (1 Jahr) voreingestellt

## 2025-01-06: Bugfix - created_at für licenses Tabelle

**Problem:**
- Batch-Generierung schlug fehl mit "Fehler bei der Batch-Generierung!"
- INSERT Statement versuchte `created_at` zu setzen, aber Spalte existierte nicht
- Inkonsistenz: Einzellizenzen hatten kein created_at, Batch-Lizenzen versuchten es zu setzen

**Lösung:**
1. **Datenbank-Schema erweitert:**
   - `created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP` zur licenses Tabelle hinzugefügt
   - Migration für bestehende Datenbanken implementiert
   - Konsistent mit customers Tabelle
2. **Code bereinigt:**
   - Explizites `created_at` aus Batch-INSERT entfernt
   - Datenbank setzt nun automatisch den Zeitstempel bei ALLEN Lizenzen

**Änderungen:**
- `init.sql`: created_at Spalte zur licenses Tabelle mit DEFAULT-Wert
- `init.sql`: Migration für bestehende Datenbanken
- `app.py`: Entfernt explizites created_at aus batch_licenses()

**Status:**
- ✅ Alle Lizenzen haben nun automatisch einen Erstellungszeitstempel
- ✅ Batch-Generierung funktioniert wieder
- ✅ Konsistente Zeitstempel für Audit-Zwecke

## 2025-01-06: Status "Deaktiviert" für manuell abgeschaltete Lizenzen

**Problem:**
- Dashboard zeigte nur "aktiv" und "abgelaufen" als Status
- Manuell deaktivierte Lizenzen (is_active = FALSE) wurden nicht korrekt angezeigt
- Filter für "inactive" existierte, aber Status wurde nicht richtig berechnet

**Lösung:**
1. **Status-Berechnung erweitert:**
   - CASE-Statement prüft zuerst `is_active = FALSE`
   - Status "deaktiviert" wird vor anderen Status geprüft
   - Reihenfolge: deaktiviert → abgelaufen → läuft bald ab → aktiv
2. **Dashboard-Statistik erweitert:**
   - Neue Zählung für deaktivierte Lizenzen
   - Variable `inactive_licenses` im stats Dictionary

**Änderungen:**
- `app.py`: Dashboard - Status-Berechnung für letzte 5 Lizenzen
- `app.py`: Lizenzübersicht - Status-Berechnung in der Hauptabfrage
- `app.py`: Export - Status-Berechnung für CSV/Excel Export
- `app.py`: Dashboard - Neue Statistik für deaktivierte Lizenzen

**Status:**
- ✅ "Deaktiviert" wird korrekt als Status angezeigt
- ✅ Dashboard zeigt Anzahl deaktivierter Lizenzen
- ✅ Export enthält korrekten Status
- ✅ Konsistente Status-Anzeige überall

## 2025-06-08: SSL-Sicherheit verbessert - Chrome Warnung behoben

**Problem:**
- Chrome zeigte Warnung "Die Verbindung zu dieser Website ist nicht sicher"
- Nginx erlaubte schwache Cipher Suites (WEAK) ohne Perfect Forward Secrecy
- Veraltete SSL-Konfiguration mit `ssl_ciphers HIGH:!aNULL:!MD5;`

**Lösung:**
1. **Moderne Cipher Suite Konfiguration:**
   - Nur sichere ECDHE und DHE Cipher Suites
   - Entfernung aller RSA-only Cipher Suites
   - Perfect Forward Secrecy für alle Verbindungen
2. **SSL-Optimierungen:**
   - Session Cache aktiviert (1 Tag Timeout)
   - OCSP Stapling für bessere Performance
   - DH Parameters (2048 bit) für zusätzliche Sicherheit
3. **Resolver-Konfiguration:**
   - Google DNS Server für OCSP Stapling

**Änderungen:**
- `v2_nginx/nginx.conf`: Komplett überarbeitete SSL-Konfiguration
- `v2_nginx/ssl/dhparam.pem`: Neue 2048-bit DH Parameters generiert
- `v2_nginx/Dockerfile`: COPY Befehl für dhparam.pem hinzugefügt

**Status:**
- ✅ Nur noch sichere Cipher Suites aktiv
- ✅ Perfect Forward Secrecy gewährleistet
- ✅ OCSP Stapling aktiviert
- ✅ Chrome Sicherheitswarnung behoben

**Hinweis:** Nach dem Rebuild des nginx Containers wird die Verbindung als sicher angezeigt.

## 2025-06-08: CAPTCHA-Login-Bug behoben

**Problem:**
- Nach 2 fehlgeschlagenen Login-Versuchen wurde CAPTCHA angezeigt
- Da keine CAPTCHA-Keys konfiguriert waren (für PoC), konnte man sich nicht mehr einloggen
- Selbst mit korrektem Passwort war Login blockiert
- Fehlermeldung "CAPTCHA ERFORDERLICH!" erschien immer

**Lösung:**
1. **CAPTCHA-Prüfung nur wenn Keys vorhanden:**
   - `recaptcha_site_key` wird vor CAPTCHA-Prüfung geprüft
   - Wenn keine Keys konfiguriert → kein CAPTCHA-Check
   - CAPTCHA wird nur angezeigt wenn Keys existieren
2. **Template-Anpassungen:**
   - login.html zeigt CAPTCHA nur wenn `recaptcha_site_key` vorhanden
   - Kein Test-Key mehr als Fallback
3. **Konsistente Logik:**
   - show_captcha prüft jetzt auch ob Keys vorhanden sind
   - Bei GET und POST Requests gleiche Logik

**Änderungen:**
- `v2_adminpanel/app.py`: CAPTCHA-Check nur wenn `RECAPTCHA_SITE_KEY` existiert
- `v2_adminpanel/templates/login.html`: CAPTCHA nur anzeigen wenn Keys vorhanden

**Status:**
- ✅ Login funktioniert wieder nach 2+ Fehlversuchen
- ✅ CAPTCHA wird nur angezeigt wenn Keys konfiguriert sind
- ✅ Für PoC-Phase ohne CAPTCHA nutzbar
- ✅ Produktiv-ready wenn CAPTCHA-Keys eingetragen werden

### 2025-06-08: Zeitzone auf Europe/Berlin umgestellt

**Problem:**
- Alle Zeitstempel wurden in UTC gespeichert und angezeigt
- Backup-Dateinamen zeigten UTC-Zeit statt deutsche Zeit
- Verwirrung bei Zeitangaben im Admin Panel und Logs

**Lösung:**
1. **Docker Container Zeitzone konfiguriert:**
   - Alle Dockerfiles mit `TZ=Europe/Berlin` und tzdata Installation
   - PostgreSQL mit `PGTZ=Europe/Berlin` für Datenbank-Zeitzone
   - Explizite Zeitzone-Dateien in /etc/localtime und /etc/timezone

2. **Python Code angepasst:**
   - Import von `zoneinfo.ZoneInfo` für Zeitzonenunterstützung
   - Alle `datetime.now()` Aufrufe mit `ZoneInfo("Europe/Berlin")`
   - `.replace(tzinfo=None)` für Kompatibilität mit timezone-unaware Timestamps

3. **PostgreSQL Konfiguration:**
   - `SET timezone = 'Europe/Berlin';` in init.sql
   - Umgebungsvariablen TZ und PGTZ in docker-compose.yaml

4. **docker-compose.yaml erweitert:**
   - `TZ: Europe/Berlin` für alle Services

**Geänderte Dateien:**
- `v2_adminpanel/Dockerfile`: Zeitzone und tzdata hinzugefügt
- `v2_postgres/Dockerfile`: Zeitzone und tzdata hinzugefügt
- `v2_nginx/Dockerfile`: Zeitzone und tzdata hinzugefügt
- `v2_lizenzserver/Dockerfile`: Zeitzone und tzdata hinzugefügt
- `v2_adminpanel/app.py`: 14 datetime.now() Aufrufe mit Zeitzone versehen
- `v2_adminpanel/init.sql`: PostgreSQL Zeitzone gesetzt
- `v2/docker-compose.yaml`: TZ Environment-Variable für alle Services

**Ergebnis:**
- ✅ Alle neuen Zeitstempel werden in deutscher Zeit (Europe/Berlin) gespeichert
- ✅ Backup-Dateinamen zeigen korrekte deutsche Zeit
- ✅ Admin Panel zeigt alle Zeiten in deutscher Zeitzone
- ✅ Automatische Anpassung bei Sommer-/Winterzeit
- ✅ Konsistente Zeitangaben über alle Komponenten

**Hinweis:** Nach diesen Änderungen müssen die Docker Container neu gebaut werden:
```bash
docker-compose down
docker-compose build
docker-compose up -d
```

### 2025-06-08: Zeitzone-Fix - PostgreSQL Timestamps

**Problem nach erster Implementierung:**
- Trotz Zeitzoneneinstellung wurden Zeiten immer noch in UTC angezeigt
- Grund: PostgreSQL Tabellen verwendeten `TIMESTAMP WITHOUT TIME ZONE`

**Zusätzliche Lösung:**
1. **Datenbankschema angepasst:**
   - Alle `TIMESTAMP` Spalten auf `TIMESTAMP WITH TIME ZONE` geändert
   - Betrifft: created_at, timestamp, started_at, ended_at, last_heartbeat, etc.
   - Migration für bestehende Datenbanken berücksichtigt

2. **SQL-Abfragen vereinfacht:**
   - `AT TIME ZONE 'Europe/Berlin'` nicht mehr nötig
   - PostgreSQL handhabt Zeitzonenkonvertierung automatisch

**Geänderte Datei:**
- `v2_adminpanel/init.sql`: Alle TIMESTAMP Felder mit WITH TIME ZONE

**Wichtig:** Bei bestehenden Installationen muss die Datenbank neu initialisiert oder manuell migriert werden:
```sql
ALTER TABLE customers ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE licenses ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE sessions ALTER COLUMN started_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE sessions ALTER COLUMN last_heartbeat TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE sessions ALTER COLUMN ended_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE audit_log ALTER COLUMN timestamp TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE backup_history ALTER COLUMN created_at TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE login_attempts ALTER COLUMN first_attempt TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE login_attempts ALTER COLUMN last_attempt TYPE TIMESTAMP WITH TIME ZONE;
ALTER TABLE login_attempts ALTER COLUMN blocked_until TYPE TIMESTAMP WITH TIME ZONE;
```