Browse Source

feat: Add Paperless service integration

- Updated `.gitignore` to exclude `node_modules` for Paperless setup.
- Extended Ansible `main.yml` with Paperless OIDC configuration.
- Added Paperless service configuration to Ansible tasks.
- Introduced Paperless-related variables in Ansible defaults.
- Adjusted NGINX configurations for Keycloak, Nextcloud, and Paperless.
- Included Paperless environment variables in `docker/.env`.
- Updated `docker-compose.yml` with Paperless, database, and Redis services.
- Created Paperless Docker setup in `docs/context/configuration/docker-compose.yml`.

Supports Paperless deployment with OpenID Connect authentication and Docker container setup.
mrx8086 11 months ago
parent
commit
2ccc84e275

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 data/
 data/
 config/credentials
 config/credentials
 config/nextcloud/
 config/nextcloud/
+scripts/setup/paperless/node_modules

+ 10 - 1
ansible/roles/services/defaults/main.yml

@@ -20,4 +20,13 @@ sso_config:
         nextcloud-youpi: "youpi"
         nextcloud-youpi: "youpi"
 
 
 # Default paths and settings
 # Default paths and settings
-nextcloud_data_dir: "/var/www/html/data"
+nextcloud_data_dir: "/var/www/html/data"
+
+# ansible/roles/services/defaults/main.yml
+paperless_oidc:
+  client_id: paperless
+  provider_url: "https://{{ keycloak_host }}"
+  realm: "{{ keycloak_realm }}"
+  sign_algo: "RS256"
+  verify_ssl: false
+  scopes: "openid profile email"

+ 12 - 1
ansible/roles/services/tasks/main.yml

@@ -120,4 +120,15 @@
 
 
 - name: "Display SSO configuration"
 - name: "Display SSO configuration"
   debug:
   debug:
-    var: sso_config_verification.stdout
+    var: sso_config_verification.stdout
+
+# ansible/roles/services/tasks/main.yml
+- name: Configure Paperless
+  block:
+    - name: Setup Paperless Django settings
+      template:
+        src: paperless_django_settings.j2
+        dest: "{{ paperless_config_dir }}/django/settings.py"
+      tags: 
+        - paperless
+        - paperless-config

+ 35 - 0
ansible/roles/services/templates/paperless_django_settings.j2

@@ -0,0 +1,35 @@
+# ansible/roles/services/templates/paperless_django_settings.j2
+import os
+
+PAPERLESS_ENABLE_OIDC = True
+OIDC_RP_CLIENT_ID = "{{ paperless_oidc_client_id }}"
+OIDC_RP_CLIENT_SECRET = os.getenv('PAPERLESS_CLIENT_SECRET')
+OIDC_RP_SIGN_ALGO = "RS256"
+OIDC_VERIFY_SSL = False
+
+OIDC_OP_AUTHORIZATION_ENDPOINT = "https://{{ keycloak_host }}/realms/{{ keycloak_realm }}/protocol/openid-connect/auth"
+OIDC_OP_TOKEN_ENDPOINT = "https://{{ keycloak_host }}/realms/{{ keycloak_realm }}/protocol/openid-connect/token"
+OIDC_OP_USER_ENDPOINT = "https://{{ keycloak_host }}/realms/{{ keycloak_realm }}/protocol/openid-connect/userinfo"
+OIDC_OP_JWKS_ENDPOINT = "https://{{ keycloak_host }}/realms/{{ keycloak_realm }}/protocol/openid-connect/certs"
+
+OIDC_RP_SCOPES = "openid profile email"
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'handlers': {
+        'console': {
+            'class': 'logging.StreamHandler',
+        },
+    },
+    'root': {
+        'handlers': ['console'],
+        'level': 'DEBUG',
+    },
+    'loggers': {
+        'mozilla_django_oidc': {
+            'handlers': ['console'],
+            'level': 'DEBUG'
+        },
+    }
+}

+ 6 - 0
ansible/vars/defaults/main.yml

@@ -19,3 +19,9 @@ nodered_port: 1880
 
 
 # Docker-Konfiguration
 # Docker-Konfiguration
 docker_compose_version: "2.21.0"
 docker_compose_version: "2.21.0"
+
+# Paperless Variables
+paperless_base_dir: /path/to/your/paperless
+paperless_oidc_client_id: paperless
+keycloak_host: auth.mrx8086.com
+keycloak_realm: office-automation

+ 1 - 1
config/nginx/sites-available/keycloak

@@ -1,5 +1,5 @@
 upstream keycloak_upstream {
 upstream keycloak_upstream {
-    server 172.18.0.3:8080;
+    server 172.19.0.3:8080;
 }
 }
 
 
 server {
 server {

+ 1 - 1
config/nginx/sites-available/nextcloud

@@ -1,5 +1,5 @@
 upstream nextcloud_upstream {
 upstream nextcloud_upstream {
-    server 172.19.0.3:80;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP IST
+    server 172.20.0.3:80;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP IST
 }
 }
 
 
 server {
 server {

+ 40 - 20
config/nginx/sites-available/paperless

@@ -1,41 +1,61 @@
-# HTTP-Weiterleitung auf HTTPS
+upstream paperless_upstream {
+    server 172.18.0.4:8000;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP UND DER PORT IST
+}
+
 server {
 server {
     listen 80;
     listen 80;
     server_name docs.mrx8086.com;
     server_name docs.mrx8086.com;
-
-    # Weiterleitung von HTTP zu HTTPS
     return 301 https://$host$request_uri;
     return 301 https://$host$request_uri;
 }
 }
 
 
-# HTTPS-Server
 server {
 server {
     listen 443 ssl;
     listen 443 ssl;
     server_name docs.mrx8086.com;
     server_name docs.mrx8086.com;
 
 
-    # SSL-Zertifikate einbinden
+    # SSL Configuration
     ssl_certificate /etc/nginx/ssl/mrx8086.com/fullchain.pem;
     ssl_certificate /etc/nginx/ssl/mrx8086.com/fullchain.pem;
     ssl_certificate_key /etc/nginx/ssl/mrx8086.com/privkey.pem;
     ssl_certificate_key /etc/nginx/ssl/mrx8086.com/privkey.pem;
 
 
-    # Empfohlene SSL-Einstellungen (optional)
     ssl_protocols TLSv1.2 TLSv1.3;
     ssl_protocols TLSv1.2 TLSv1.3;
     ssl_prefer_server_ciphers on;
     ssl_prefer_server_ciphers on;
-    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
-    ssl_session_cache shared:SSL:10m;
-    ssl_session_timeout 10m;
+    ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305';
+    ssl_session_timeout 1d;
+    ssl_session_cache shared:MozSSL:10m;
+    ssl_session_tickets off;
 
 
+    # Security headers
+    add_header X-Content-Type-Options nosniff always;
+    add_header X-XSS-Protection "1; mode=block" always;
+    add_header X-Frame-Options SAMEORIGIN always;
     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
-    add_header X-Content-Type-Options nosniff;
-    add_header X-Frame-Options DENY;
-    add_header X-XSS-Protection "1; mode=block";
+    add_header Content-Security-Policy "frame-ancestors 'self'; default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; media-src 'self';" always;
+
+    # Proxy settings
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Forwarded-Proto $scheme;
+    proxy_set_header X-Forwarded-Host $host;
+    proxy_set_header X-Forwarded-Port 443;
+    proxy_set_header Host $host;
+    proxy_http_version 1.1;
 
 
-    # Paperless-NGX Konfiguration
+    # Paperless specific settings
+    client_max_body_size 512M;
+    fastcgi_buffers 64 4K;
+
+    # Root location
     location / {
     location / {
-        proxy_pass http://127.0.0.1:8000;  # Paperless läuft auf Port 8000 innerhalb des Docker-Containers
-        proxy_set_header Host $host;
-        proxy_set_header X-Real-IP $remote_addr;
-        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-        proxy_set_header X-Forwarded-Proto https;
-        proxy_set_header X-Forwarded-Port 443;
+        proxy_pass http://paperless_upstream;
+        proxy_set_header Upgrade $http_upgrade;
+        proxy_set_header Connection "upgrade";
+        proxy_connect_timeout 60s;
+        proxy_send_timeout 60s;
+        proxy_read_timeout 60s;
     }
     }
-}
 
 
+    # Deny access to hidden files
+    location ~ /\. {
+        deny all;
+        return 404;
+    }
+}

+ 0 - 0
config/paperless/media/media.lock


+ 46 - 1
docker/.env

@@ -11,4 +11,49 @@ NEXTCLOUD_DB_USER=nextcloud
 NEXTCLOUD_DB_PASSWORD=YeTn4f1IIM9a7I3Q7oZNaEhs
 NEXTCLOUD_DB_PASSWORD=YeTn4f1IIM9a7I3Q7oZNaEhs
 NEXTCLOUD_DB_ROOT_PASSWORD=rY26aXw9uMOqz2BjtevQ4oKB
 NEXTCLOUD_DB_ROOT_PASSWORD=rY26aXw9uMOqz2BjtevQ4oKB
 NEXTCLOUD_ADMIN_USER=admin
 NEXTCLOUD_ADMIN_USER=admin
-NEXTCLOUD_ADMIN_PASSWORD=jTjRBEJb2ZSAH0iJoqeZijYL
+NEXTCLOUD_ADMIN_PASSWORD=jTjRBEJb2ZSAH0iJoqeZijYL
+
+
+
+# ==============================================================================
+# Paperless Environment Variables
+# ==============================================================================
+
+# Datenbank-Konfiguration
+# ------------------------------------------------------------------------------
+# Benutzername für die Paperless-Datenbank
+PAPERLESS_DB_USER=paperless
+
+# Passwort für die Paperless-Datenbank
+PAPERLESS_DB_PASSWORD=sq812ylB1Lfk49xbP8xxNSDA
+
+# Datenbank Name
+PAPERLESS_DB_NAME=paperless
+
+# Paperless Admin User
+# ------------------------------------------------------------------------------
+# Benutzername für den Paperless Admin Account
+PAPERLESS_ADMIN_USER=admin
+
+# Passwort für den Paperless Admin Account
+PAPERLESS_ADMIN_PASSWORD=GRnrM1lrMl63E16HgZk8PBXU
+
+# Paperless Secret Key
+# ------------------------------------------------------------------------------
+# Geheimer Schlüssel für Paperless (wird für Django benötigt)
+# Sollte ein zufälliger, sicherer String sein
+PAPERLESS_SECRET_KEY=qfQ7MeGB79F6nbTgFk99K2Nx
+
+# Paperless OpenID Connect (Keycloak) Konfiguration
+# ------------------------------------------------------------------------------
+# Client ID für Paperless in Keycloak
+PAPERLESS_CLIENT_ID=paperless
+
+# Client Secret für Paperless in Keycloak
+PAPERLESS_CLIENT_SECRET=CSbw9ldbZBUGGQSJoAUEg10QKgjdb6Tq
+
+# Die URL von Paperless
+PAPERLESS_URL=https://docs.mrx8086.com
+
+# Erlaubte Hosts für Paperless
+PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com

+ 94 - 0
docker/docker-compose.yml

@@ -117,8 +117,102 @@ services:
     networks:
     networks:
       - nextcloud-network
       - nextcloud-network
 
 
+  paperless:
+    image: ghcr.io/paperless-ngx/paperless-ngx:latest
+    container_name: paperless
+    restart: unless-stopped
+    ports:
+      - "8000:8000"
+    volumes:
+      - ../data/paperless:/usr/src/paperless/data
+      - ../config/paperless/media:/usr/src/paperless/media
+      - ../config/paperless/export:/usr/src/paperless/export
+      - ../config/paperless/consume:/usr/src/paperless/consume
+    environment:
+      # Basis-Konfiguration
+      - PAPERLESS_ADMIN_USER=${PAPERLESS_ADMIN_USER}
+      - PAPERLESS_ADMIN_PASSWORD=${PAPERLESS_ADMIN_PASSWORD}
+      - PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY}
+      - PAPERLESS_URL=https://docs.mrx8086.com
+      - PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com
+      - PAPERLESS_REDIS=redis://paperless-redis:6379
+      - PAPERLESS_LOGGING_DIR=/dev/stdout
+      - PAPERLESS_LOGGING_LEVEL=DEBUG
+      - DJANGO_LOG_LEVEL=DEBUG
+      
+      # OIDC Basis-Einstellungen
+      - PAPERLESS_ENABLE_OIDC=true
+      - PAPERLESS_OIDC_RP_PROVIDER_URL=https://auth.mrx8086.com/realms/office-automation
+      - PAPERLESS_OIDC_RP_CLIENT_ID=paperless
+      - PAPERLESS_OIDC_RP_CLIENT_SECRET=${PAPERLESS_CLIENT_SECRET}
+      
+      # OIDC Endpoints
+      - PAPERLESS_OIDC_AUTH_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/auth
+      - PAPERLESS_OIDC_TOKEN_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/token
+      - PAPERLESS_OIDC_USERINFO_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/userinfo
+      - PAPERLESS_OIDC_JWKS_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/certs
+      
+      # OIDC Claims und Scopes
+      - PAPERLESS_OIDC_RP_SCOPE=openid profile email
+      - PAPERLESS_OIDC_RP_USERNAME_CLAIM=preferred_username
+      - PAPERLESS_OIDC_RP_NAME_CLAIM=name
+      - PAPERLESS_OIDC_RP_EMAIL_CLAIM=email
+      
+      # OIDC Sicherheitseinstellungen
+      - PAPERLESS_OIDC_RP_SIGN_ALGO=RS256
+      - PAPERLESS_OIDC_RP_VERIFY_SSL=false
+      - PAPERLESS_OIDC_USE_PKCE=true
+      
+      # OIDC Token-Management
+      - PAPERLESS_OIDC_RP_RENEW_TOKEN_BEFORE_EXPIRY=true
+    
+    depends_on:
+      - paperless-db
+      - paperless-redis
+    networks:
+      - paperless-network
+    extra_hosts:
+      - "auth.mrx8086.com:172.23.171.133"
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8000/"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+
+  paperless-db:
+    image: postgres:15
+    container_name: paperless-db
+    restart: unless-stopped
+    environment:
+      POSTGRES_USER: ${PAPERLESS_DB_USER}
+      POSTGRES_PASSWORD: ${PAPERLESS_DB_PASSWORD}
+      POSTGRES_DB: paperless
+    volumes:
+      - ../data/paperless-db:/var/lib/postgresql/data
+    networks:
+      - paperless-network
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${PAPERLESS_DB_USER} -d paperless"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+  
+  paperless-redis:
+    image: redis:7
+    container_name: paperless-redis
+    restart: unless-stopped
+    networks:
+      - paperless-network
+    healthcheck:
+      test: ["CMD", "redis-cli", "ping"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+
 networks:
 networks:
   keycloak-network:
   keycloak-network:
     driver: bridge
     driver: bridge
   nextcloud-network:
   nextcloud-network:
+    driver: bridge
+  paperless-network:
     driver: bridge
     driver: bridge

+ 58 - 0
docs/context/configuration/docker-compose.yml

@@ -100,8 +100,66 @@ services:
     networks:
     networks:
       - nextcloud-network
       - nextcloud-network
 
 
+  paperless:
+    image: ghcr.io/paperless-ngx/paperless-ngx:latest
+    container_name: paperless
+    restart: unless-stopped
+    ports:
+      - "8000:8000"
+    volumes:
+      - ../data/paperless:/usr/src/paperless/data
+      - ../config/paperless/media:/usr/src/paperless/media
+      - ../config/paperless/export:/usr/src/paperless/export
+      - ../config/paperless/consume:/usr/src/paperless/consume
+    environment:
+      - PAPERLESS_ADMIN_USER=${PAPERLESS_ADMIN_USER}
+      - PAPERLESS_ADMIN_PASSWORD=${PAPERLESS_ADMIN_PASSWORD}
+      - PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY}
+      - PAPERLESS_URL=https://docs.mrx8086.com
+      - PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com
+      - PAPERLESS_ENABLE_OIDC=true
+      - PAPERLESS_OIDC_RP_CLIENT_ID=${PAPERLESS_CLIENT_ID}
+      - PAPERLESS_OIDC_RP_CLIENT_SECRET=${PAPERLESS_CLIENT_SECRET}
+      - PAPERLESS_OIDC_RP_PROVIDER_URL=https://auth.mrx8086.com/realms/office-automation
+      - PAPERLESS_OIDC_RP_USERNAME_CLAIM=preferred_username
+      - PAPERLESS_OIDC_RP_NAME_CLAIM=name
+      - PAPERLESS_OIDC_RP_EMAIL_CLAIM=email
+      - PAPERLESS_OIDC_RP_RENEW_TOKEN_BEFORE_EXPIRY=true
+      - PAPERLESS_OIDC_RP_VERIFY_SSL=false
+    depends_on:
+      - paperless-db
+    networks:
+      - paperless-network
+    extra_hosts:
+      - "auth.mrx8086.com:172.23.171.133"
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:8000/"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+
+  paperless-db:
+    image: postgres:15
+    container_name: paperless-db
+    restart: unless-stopped
+    environment:
+      POSTGRES_USER: ${PAPERLESS_DB_USER}
+      POSTGRES_PASSWORD: ${PAPERLESS_DB_PASSWORD}
+      POSTGRES_DB: paperless
+    volumes:
+      - ../data/paperless-db:/var/lib/postgresql/data
+    networks:
+      - paperless-network
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${PAPERLESS_DB_USER} -d paperless"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+
 networks:
 networks:
   keycloak-network:
   keycloak-network:
     driver: bridge
     driver: bridge
   nextcloud-network:
   nextcloud-network:
+    driver: bridge
+  paperless-network:
     driver: bridge
     driver: bridge

+ 1244 - 823
git_diff.txt

@@ -1,823 +1,1244 @@
-Vielen Dank für die Bereitstellung der Dateien. Ich habe alle notwendigen Informationen, um die Dokumentation zu erstellen. Hier ist der Inhalt der finalen Dokumentationsdateien:
-
-```markdown
-# Automatisiertes Büro 2.0 - Projektdokumentation
-
-## Inhaltsverzeichnis
-1.  [Projektübersicht](#projektübersicht)
-2.  [Systemarchitektur](#systemarchitektur)
-3.  [Entwicklungsumgebung](#entwicklungsumgebung)
-4.  [Konfigurationen](#konfigurationen)
-5.  [Installationsanleitung](#installationsanleitung)
-6.  [Workflows](#workflows)
-7.  [Sicherheitskonzept](#sicherheitskonzept)
-8.  [Wartung und Monitoring](#wartung-und-monitoring)
-9.  [Troubleshooting](#troubleshooting)
-
-## Projektübersicht
-
-### Projektziele
-- Vollständige Automatisierung administrativer und kaufmännischer Prozesse
-- Kostensenkung durch lokale Open-Source-Lösungen
-- Unabhängigkeit von externen Diensten
-- Zentralisierte Verwaltung aller Geschäftsprozesse
-
-### Projektumfang
-- Integration aller Kommunikationskanäle
-- Automatisierte Dokumentenverarbeitung
-- Prozessautomatisierung
-- Zentrale Authentifizierung
-- KI-gestützte Korrespondenz
-
-#### Keycloak-Rolle
-Keycloak spielt eine zentrale Rolle als Authentifizierungsstelle. Es stellt die Single-Sign-On (SSO) Funktionalität für alle Dienste der zentralen Plattform bereit und sichert somit den Zugriff auf die verschiedenen Anwendungen.
-
-## Systemarchitektur
-
-#### Architekturübersicht
-
-```mermaid
-graph TB
-    subgraph Eingangssysteme
-        Email[E-Mail]
-        WhatsApp[WhatsApp]
-        Post[Physische Post]
-        Teams[Teams/Webex]
-    end
-
-    subgraph Zentrale_Plattform
-        NC[Nextcloud - Dokumentenverwaltung]
-        PL[Paperless - Dokumentenmanagement]
-        NR[Node-RED - Prozessautomatisierung]
-        KC[Keycloak - SSO]
-        OUI[OpenWebUI - KI-Korrespondenz]
-		KI[Kimai - Zeiterfassung]
-    end
-
-    subgraph Monitoring_Analytics
-        ELK[ELK Stack - Logging & Analyse]
-    end
-
-    subgraph Geschäftsprozesse
-        TP[Task-Priorisierung]
-        subgraph Finanzen
-            RE[Rechnungserstellung]
-            ZA[Zahlungsabwicklung]
-            BA[Banken-API]
-        end
-        subgraph Verwaltung
-            KV[Kundenverwaltung]
-            ZE[Zeiterfassung]
-            DO[Dokumentenarchiv]
-        end
-    end
-
-    Email --> NC
-    WhatsApp --> NC
-    Post --> PL
-    Teams --> NC
-
-    NC --> NR
-    PL --> NR
-    NR --> TP
-	KI --> TP
-
-    TP --> RE
-    TP --> ZA
-    TP --> KV
-    TP --> ZE
-    TP --> DO
-
-    ZA <--> BA
-
-    KC -.->|Authentifizierung| NC
-    KC -.->|Authentifizierung| PL
-    KC -.->|Authentifizierung| NR
-    KC -.->|Authentifizierung| OUI
-	KC -.->|Authentifizierung| KI
-
-    NR --> ELK
-    OUI --> NR
-
-    classDef container fill:#e1f5fe,stroke:#01579b
-    classDef process fill:#e8f5e9,stroke:#2e7d32
-    classDef auth fill:#fff3e0,stroke:#ef6c00
-    classDef monitoring fill:#fce4ec,stroke:#c2185b
-
-    class NC,PL,NR,KI container
-    class TP,RE,ZA,KV,ZE,DO process
-    class KC auth
-    class ELK monitoring
-```
-
-#### Beschreibung der Architekturkomponenten
-
-Die Systemarchitektur ist in vier Hauptbereiche gegliedert:
-
-1.  **Eingangssysteme:**
-    - Erfassen verschiedene Kommunikationskanäle zentral.
-    - Sorgen für eine einheitliche Weiterverarbeitung aller Eingänge.
-
-2.  **Zentrale Plattform:**
-    - **Nextcloud (NC):** Dient als zentraler Hub für die Dateiverwaltung und Kollaboration.
-    - **Paperless (PL):** Zuständig für das Dokumentenmanagement und die optische Zeichenerkennung (OCR).
-    - **Node-RED (NR):** Automatisierung von Workflows und Geschäftsprozessen.
-    - **Keycloak (KC):** Bereitstellung von Single-Sign-On (SSO) und Identitätsmanagement.
-        - Keycloak wird als zentrale Authentifizierungsstelle für alle Dienste der zentralen Plattform verwendet, wodurch ein sicherer und zentralisierter Zugriff gewährleistet wird.
-    - **OpenWebUI (OUI):** KI-gestützte Kommunikation und Integration in die Workflow-Automatisierung
-    - **Kimai (KI):** Zeiterfassungslösung zur Verwaltung von Arbeitszeiten und Projekten.
-
-3.  **Geschäftsprozesse:**
-    - Automatisierte Task-Priorisierung (TP) für eine effiziente Aufgabenverteilung.
-    - Integrierte Finanzprozesse mit Bankenanbindung (RE, ZA, BA).
-    - Zentralisierte Verwaltungsprozesse (KV, ZE, DO).
-
-4.  **Monitoring & Analytics:**
-    - **ELK Stack (ELK):** Ermöglicht umfassendes Logging und Analyse in Echtzeit zur Überwachung aller Systeme.
-
-#### Containerstruktur
-- Docker als Containerisierungsplattform
-- Microservices-Architektur
-- Interne Netzwerkkonfiguration
-
-### Komponenten
-#### Nextcloud
-- Funktion: Zentrale Dateiverwaltung und Kollaboration
-- Version: `[VERSION]`
-- Besondere Konfigurationen:
-  - [Wird ergänzt]
-
-#### Paperless
-- Funktion: Dokumentenmanagement und OCR
-- Version: `[VERSION]`
-- Besondere Konfigurationen:
-  - [Wird ergänzt]
-
-#### Keycloak
-- Funktion: Single-Sign-On und Identitätsmanagement
-- Version: `[VERSION]`
-- Besondere Konfigurationen:
-  - [Wird ergänzt]
-
-#### Node-RED
-- Funktion: Workflow-Automatisierung
-- Version: `[VERSION]`
-- Implementierte Flows:
-  - [Wird ergänzt]
-
-#### ELK Stack
-- Funktion: Logging und Monitoring
-- Version: `[VERSION]`
-- Besondere Konfigurationen:
-  - [Wird ergänzt]
-
-#### OpenWebUI
-- Funktion: KI-gestützte Kommunikation
-- Version: `[VERSION]`
-- Integrationen:
-  - [Wird ergänzt]
-
-#### Kimai
-- Funktion: Zeiterfassung
-- Version: `[VERSION]`
-- Besondere Konfigurationen:
-  - [Wird ergänzt]
-
-## Entwicklungsumgebung
-
-### Systemvoraussetzungen
-- Windows mit WSL (Windows Subsystem for Linux)
-- Visual Studio Code
-- Docker Desktop
-- NGINX Proxy Manager (läuft in WSL)
-
-#### Domain-Konfiguration
-Die Entwicklungsumgebung nutzt die Domain `mrx8086.com` mit verschiedenen Subdomains für die einzelnen Services. Diese werden lokal über die Windows-Hosts-Datei (`C:\Windows\System32\drivers\etc\hosts`) aufgelöst.
-
-```plaintext
-# Development Environment Host Entries
-127.0.0.1 mrx8086.com
-127.0.0.1 proxy.mrx8086.com     # NGINX Proxy Manager
-172.23.171.133 auth.mrx8086.com # Keycloak
-127.0.0.1 cloud.mrx8086.com     # Nextcloud
-127.0.0.1 docs.mrx8086.com      # Paperless
-127.0.0.1 time.mrx8086.com      # Kimai
-127.0.0.1 automate.mrx8086.com  # n8n
-```
-
-#### Service-Übersicht
-| Subdomain | Service | Beschreibung |
-|-----------|---------|--------------|
-| proxy.mrx8086.com | NGINX Proxy Manager | Reverse Proxy und SSL-Management (lokal in der Development Umgebung) |
-| auth.mrx8086.com | Keycloak | Zentrale Authentifizierung |
-| cloud.mrx8086.com | Nextcloud | Dokumentenverwaltung |
-| docs.mrx8086.com | Paperless | Dokumentenmanagement |
-| time.mrx8086.com | Kimai | Zeiterfassung |
-| automate.mrx8086.com | n8n | Workflow-Automatisierung |
-
-#### WSL-Konfiguration
-- NGINX Proxy Manager läuft in WSL
-- IP-Adresse des WSL-Systems: 172.23.171.133 (Beispiel, kann sich ändern)
-- Alle Docker-Container werden innerhalb von WSL betrieben
-
-#### `setup_realm.js`
-Dieses Skript wird verwendet, um den Keycloak-Realm, die zugehörigen Clients und Testbenutzer automatisiert zu erstellen. Es verwendet eine `.env`-Datei zur Konfiguration.
-
-#### Verwendung von .env
-Die Konfigurationen für das setup_realm.js Script werden in einer .env Datei gespeichert. Die benötigten Umgebungsvariablen sind unten aufgelistet:
-- `KEYCLOAK_URL`: Die URL zum Keycloak Server (z.B. https://auth.mrx8086.com)
-- `KEYCLOAK_ADMIN_USER`: Der Benutzername des Keycloak Administrators (z.B. admin).
-- `KEYCLOAK_ADMIN_PASSWORD`: Das Passwort des Keycloak Administrators.
-- `NEXTCLOUD_CLIENT_ID`: Die Client ID für Nextcloud. (z.B. nextcloud)
-- `PAPERLESS_CLIENT_ID`: Die Client ID für Paperless (z.B. paperless).
-- `NODERED_CLIENT_ID`: Die Client ID für Node-RED (z.B. nodered).
-- `TESTADMIN_PASSWORD`: Das Passwort für den Testadmin User.
-- `TESTUSER_PASSWORD`: Das Passwort für den Testuser User.
-- `TESTSERVICEUSER_PASSWORD`: Das Passwort für den Testserviceuser User.
-- `KEYCLOAK_NEXTCLOUD_CLIENT_SECRET`: Das Client Secret für Nextcloud.
-- `NEXTCLOUD_URL`: Die URL zur Nextcloud Instanz (z.B. https://cloud.mrx8086.com).
-
-#### NGINX-Konfigurationen
-Für jeden Service existiert eine dedizierte NGINX-Konfiguration. In der Development Umgebung wird der **NGINX Proxy Manager** verwendet. Für **Staging** und **Production** werden die entsprechenden NGINX Konfigurationsdateien in `/config/nginx` abgelegt.
-
-## Konfigurationen
-
-### Netzwerkkonfiguration
-- Interne Netzwerkstruktur (noch zu definieren)
-- Reverse Proxy Konfiguration über den Nginx Proxy Manager in der Development Umgebung, und Nginx Server Config in Staging und Production.
-- SSL/TLS-Setup: Selbsignierte Zertifikate in der Development Umgebung, Letsencrypt in Staging und Production.
-- Konfigurationsdateien für NGINX Server Config sind unter `/config/nginx/sites-available/` zu finden.
-- Für die Entwicklungsumgebung werden die Konfigurationen über den Nginx Proxy Manager konfiguriert.
-- Die SSL Zertifikate für die Development Umgebung werden als selbsignierte Zertifikate generiert und in `/config/nginx/ssl/mrx8086.com/` abgelegt.
-- In der Staging und Production Umgebung werden die Zertifikate über Let's Encrypt oder eine andere Zertifizierungsstelle verwaltet.
-
-#### Umgebungsvariablen
-Es werden zwei `.env`-Dateien verwendet:
-Eine im `docker/` Verzeichnis für die Docker-Konfiguration und eine im `scripts/setup/keycloak/` für das `setup_realm.js`-Skript.
-
-**`docker/.env`:**
-```env
-# Generated on 2024-12-12_18-12-36
-# Keycloak Admin
-KEYCLOAK_ADMIN_PASSWORD=9aD5Fddh457QqmvQqr6Rb8bu
-
-# Keycloak Database
-KC_DB_USERNAME=keycloak
-KC_DB_PASSWORD=p47616y763z101f3
-```
-
-**`scripts/setup/keycloak/.env`:**
-```env
-KEYCLOAK_URL=https://auth.mrx8086.com
-KEYCLOAK_ADMIN_USER=admin
-KEYCLOAK_ADMIN_PASSWORD=9aD5Fddh457QqmvQqr6Rb8bu
-NEXTCLOUD_CLIENT_ID=nextcloud
-PAPERLESS_CLIENT_ID=paperless
-NODERED_CLIENT_ID=nodered
-TESTADMIN_PASSWORD=TestAdminPwd
-TESTUSER_PASSWORD=TestUserPwd
-TESTSERVICEUSER_PASSWORD=TestServiceUserPwd
-KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=OSbJ08zyjBWChwBR7S6c1q4sU0d8zvEK
-NEXTCLOUD_URL=https://cloud.mrx8086.com
-```
-
-Die Passwörter in der `.env` Datei im `scripts/setup/keycloak` werden vom `setup_environment.sh` Skript generiert.
-
-#### Keycloak-Konfiguration
-
-Keycloak ist als zentrale Authentifizierungsstelle konfiguriert. Die Realm-Konfiguration, Clients und Benutzer werden über das `setup_realm.js` Skript definiert, die Konfiguration wird über die `.env` Datei im `/scripts/setup/keycloak` Verzeichnis angepasst.
-
-##### Realm-Konfiguration
-- **Realm-Name:** `office-automation`
-- **Anzeige Name:** `Office Automation`
-- **SSL ist erforderlich**: `external`
-- **Registrierung ist nicht erlaubt**: `false`
-- **Login mit Email ist erlaubt**: `true`
-- **Doppelte Email ist nicht erlaubt**: `false`
-- **Passwort Reset ist erlaubt**: `true`
-- **Username Bearbeitung ist nicht erlaubt**: `false`
-- **Brute Force Schutz ist aktiviert**: `true`
-- **Permanente Sperrung ist nicht aktiviert**: `false`
-- **Standard Signature Algorithm**: `RS256`
-- **WebAuthn Policy Signatur Algorithmen**: `ES256`
-- **WebAuthn Policy Attestation Conveyance Preference**: `none`
-- **WebAuthn Policy Authenticator Attachment**: `cross-platform`
-- **WebAuthn Policy Require Resident Key**: `not specified`
-- **WebAuthn Policy User Verification Requirement**: `preferred`
-- **WebAuthn Policy Create Timeout**: `0`
-- **WebAuthn Policy Avoid Same Authenticator Register**: `false`
-- **Default Default Client Scopes**: `email`, `profile`, `roles`, `web-origins`
-- **Default Optional Client Scopes**: `address`, `phone`, `offline_access`, `microprofile-jwt`
-
-##### Clients
-Die folgenden Clients werden über das Skript konfiguriert:
-- **Nextcloud:**
-  -   **Client ID:** `nextcloud`
-  -   **Name:** `Nextcloud`
-   -   **Redirect URIs:**
-        - `https://cloud.mrx8086.com/apps/sociallogin/custom_oidc/keycloak`
-        - `https://cloud.mrx8086.com/apps/user_oidc/code`
-    -   **Post Logout Redirect URIs:** `https://cloud.mrx8086.com/*`
-- **Paperless:**
-  -   **Client ID:** `paperless`
-  -   **Name:** `Paperless`
-  -   **Redirect URIs:** `https://docs.mrx8086.com/*`
-- **Node-RED:**
-  -   **Client ID:** `nodered`
-  -   **Name:** `Node-RED`
-  -   **Redirect URIs:** `https://automate.mrx8086.com/*`
-
-##### Gruppen
-- **nextcloud-admins:** Gruppe für Nextcloud Benutzer mit Admin Rechten.
-- **nextcloud-users:** Gruppe für reguläre Nextcloud Benutzer.
-- **nextcloud-youpi:** Gruppe für Nextcloud Youpi Benutzer.
-- **nextcloud-service:** Gruppe für Nextcloud Service Benutzer.
-
-##### Benutzer
-- **testadmin:**
-  - Benutzername: `testadmin`
-  - Passwort: wird entweder aus der Umgebungsvariable `TESTADMIN_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
-  - Gruppen: `nextcloud-admins`,`nextcloud-users`
-- **testuser:**
-  - Benutzername: `testuser`
-  - Passwort: wird entweder aus der Umgebungsvariable `TESTUSER_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
-  - Gruppen: `nextcloud-users`,`nextcloud-youpi`
-- **testserviceuser:**
-    - Benutzername: `testserviceuser`
-    - Passwort: wird entweder aus der Umgebungsvariable `TESTSERVICEUSER_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
-    - Gruppen: `nextcloud-service`
-
-#### SSL/TLS-Setup
--   **Entwicklungsumgebung (`dev`):** Für lokale Entwicklung werden selbsignierte SSL-Zertifikate verwendet.
--   **Staging/Produktionsumgebung (`staging`, `production`):** Hier werden SSL-Zertifikate über Let's Encrypt oder eine ähnliche Zertifizierungsstelle verwaltet.
-
-## Installationsanleitung
-#### Voraussetzungen
-- Docker Version: `[VERSION]`
-- Minimal Systemanforderungen:
-  - CPU: `[ANFORDERUNG]`
-  - RAM: `[ANFORDERUNG]`
-  - Speicher: `[ANFORDERUNG]`
-- Für die Ausführung des `setup_realm.js` Skriptes wird `Node.js` benötigt
-- Die genaue Version von `Node.js` wird zu einem späteren Zeitpunkt dokumentiert.
-- Vor dem starten müssen die Passwörter generiert und die `.env` Dateien erstellt werden. Hierzu wird das `setup_environment.sh` verwendet. Dieses Skript sollte **nicht in der Produktionsumgebung** verwendet werden.
-- Das Skript erstellt die benötigten Verzeichnisse, generiert zufällige Passwörter, speichert diese verschlüsselt ab, und erstellt die benötigten `.env` Dateien.
-- Für die Ausführung des `setup_realm.js` Skriptes wird `Node.js` und `npm` benötigt
-- Die benötigten Node Module `dotenv` und `axios` können mit `npm install dotenv axios` installiert werden.
-- Die `.env` Dateien werden im `/docker` und im `/scripts/setup/keycloak` Verzeichnis abgelegt.
-
-#### Keycloak-Installation
-1.  Führe das `setup_environment.sh` Skript aus, um die .env Dateien, die Passwörter zu generieren und die Credentials zu verschlüsseln.
-2.  Kopiere die `docker-compose.yml` Datei in das `docker/` Verzeichnis.
-3.  Kopiere die `.env` Datei in das `docker/` Verzeichnis.
-4.  Führe `docker-compose up -d` im `docker/` Verzeichnis aus um Keycloak zu starten.
-
-#### Ausführen von `setup_realm.js`
-1.  Stelle sicher, dass Node.js und npm installiert sind.
-2.  Wechsle in das `/scripts/setup/keycloak` Verzeichnis.
-3.  Installiere die benötigten npm Pakete mit `npm install dotenv axios`.
-4.  Führe das Skript mit `node setup_realm.js` aus. Dies erstellt den Keycloak-Realm, die Clients und die Testbenutzer.
-    * Das Script befindet sich im `/scripts/setup/keycloak` Verzeichnis
-
-## Workflows
-#### Dokumentenverarbeitung
-- Eingangsverarbeitung
-- OCR-Prozess
-- Kategorisierung
-- Archivierung
-
-#### Geschäftsprozesse
-- Rechnungsstellung
-- Zahlungsabwicklung
-- Kundenmanagement
-- Zeiterfassung
-
-#### Authentifizierungsflow
-Die Authentifizierung der Benutzer für alle Dienste wird über Keycloak abgewickelt. Details zu den Authentifizierungsabläufen werden in einem späteren Schritt dokumentiert.
-
-## Sicherheitskonzept
-#### Zugriffsmanagement
-- Rollenkonzept (wird in späteren schritten dokumentiert)
-- Berechtigungsmatrix (wird in späteren schritten dokumentiert)
-- Authentifizierungsflows (siehe Workflows)
-- Keycloak wird als zentrale Authentifizierungsstelle verwendet, Passwortrichtlinien werden in Keycloak definiert.
-
-#### Datensicherheit
-- Verschlüsselung (wird in späteren schritten dokumentiert)
-- Backup-Strategie (wird in späteren schritten dokumentiert)
-- Notfallwiederherstellung (wird in späteren schritten dokumentiert)
-
-## Wartung und Monitoring
-#### Regelmäßige Wartungsaufgaben
-- Backup-Überprüfung
-- Updates
-- Performance-Monitoring
-
-Details zur Wartung und dem Monitoring werden in späteren Schritten dokumentiert.
-
-## Troubleshooting
-#### Bekannte Probleme
-- [Wird ergänzt mit auftretenden Problemen]
-
-#### Debugging
-- Log-Analyse
-- Fehlerbehandlung
-- Support-Prozesse
-Details zu bekannten Problemen und zur Fehlerbehandlung werden in späteren Schritten dokumentiert.
-```
-```markdown
-# Automated Office 2.0 - Current Project State
-
-## Overview
-Project to automate all administrative and commercial processes within the company, using open-source solutions.
-
-## Current Implementation Status
-
-### 1. Project Structure
-- Basic directory structure created
-- Ansible roles established (common, docker, nginx, services)
-- Configuration directories set up for all services
-- Documentation structure established
-
-### 2. Environment Setup
-- Development environment using WSL
-- NGINX running in WSL for development using NGINX Proxy Manager
-- Docker environment being set up
-- SSL certificates in place for development (self-signed)
-- Staging and Production environment will use NGINX Server Configs and letsencrypt SSL certificates
-
-### 3. Service Status
-
-#### Keycloak (auth.mrx8086.com)
-- NGINX configuration complete
-- Docker setup complete
-- Keycloak is running behind a reverse proxy
-- Implemented setup_realm.js script for automated realm, client and user setup
-- SSL certificates configured (self-signed)
-- `setup_realm.js` configures the `office-automation` realm, `nextcloud`, `paperless`, and `nodered` clients.
-- Test users `testadmin`, `testuser` and `testserviceuser` are also created.
-- Client Scopes for `openid`, `profile` and `groups-nextcloud` are added to the nextcloud client.
-- Groups `nextcloud-admins`, `nextcloud-users`, `nextcloud-youpi` and `nextcloud-service` are created.
-
-#### Nextcloud (cloud.mrx8086.com)
-- NGINX configuration complete
-- Docker setup complete
-- SSL certificates configured
-- Nextcloud is configured to use Keycloak for authentication
-
-#### Paperless (docs.mrx8086.com)
-- NGINX configuration complete
-- Docker setup pending
-- SSL certificates configured
-
-#### Node-RED (automate.mrx8086.com)
-- NGINX configuration complete
-- Docker setup pending
-- SSL certificates configured
-- Chosen over n8n for better open-source compatibility
-
-### 4. Security
-- Automated password generation implemented
-- Encrypted credentials storage system in place
-- SSL certificates managed and deployed
-
-### 5. Development Decisions
-- Using WSL for development environment
-- NGINX running directly in WSL for development
-- Docker containers for all services
-- Focusing on completely open-source solutions
-- Development environment uses Nginx Proxy Manager
-- Staging and Production will use Nginx Server Config files
-
-## Next Steps
-1. Complete Paperless and Node-RED docker setup
-2. Test Paperless and Node-RED authentication against Keycloak
-3. Proceed with remaining service deployments
-4. Setup Letsencrypt SSL Certificates in the Staging Environment
-
-## Important Files Location
-- NGINX configs: /config/nginx/sites-available/
-- SSL certificates: /config/nginx/ssl/mrx8086.com/
-- Docker compose: /docker/docker-compose.yml
-- Environment variables: /config/.env
-- Encrypted credentials: /config/credentials/
-- Keycloak setup script: /scripts/install/setup_realm.js
-
-## Development Environment
-- Domain: mrx8086.com
-- SSL certificates in place (self-signed)
-- NGINX running in WSL
-- Docker running in WSL
-```
-```markdown
-# Ansible Setup Documentation
-
-## Overview
-Ansible wird für das automatisierte Deployment des Automated Office Systems verwendet.
-
-## Roles Structure
-
-### Common Role
-- Basis-Systemkonfiguration
-- Sicherheitseinstellungen (fail2ban, UFW)
-- Grundlegende Systempakete
-
-```yaml
-# Standardvariablen
-timezone: "Europe/Berlin"
-fail2ban_bantime: 600
-fail2ban_findtime: 600
-fail2ban_maxretry: 3
-```
-
-### Docker Role
-- Docker Installation und Konfiguration
-- Docker Compose Setup
-- Docker Netzwerk-Konfiguration
-
-```yaml
-# Docker Standardvariablen
-docker_version: "latest"
-docker_compose_version: "2.21.0"
-docker_users: ["{{ ansible_user }}"]
-```
-
-### NGINX Role
-- NGINX Installation
-- SSL/TLS Setup
-- Virtual Host Konfiguration
-
-```yaml
-# NGINX Standardvariablen
-nginx_worker_processes: auto
-nginx_worker_connections: 1024
-nginx_client_max_body_size: "100M"
-```
-
-### Services Role
-- Deployment der Docker-Container
-- Service-spezifische Konfigurationen
-- Datenpersistenz-Setup
-
-## Inventory Structure
-```plaintext
-inventory/
-├── production/
-└── staging/
-    └── hosts
-```
-
-## Variables
-```yaml
-# vars/defaults/main.yml
-base_domain: "example.com"
-ssl_email: "admin@example.com"
-
-services:
-  keycloak: true
-  nextcloud: true
-  paperless: true
-  nodered: true
-```
-```yaml
-# ansible/roles/common/defaults/main.yml
----
-# System
-timezone: "Europe/Berlin"
-
-# Security
-fail2ban_bantime: 600
-fail2ban_findtime: 600
-fail2ban_maxretry: 3
-
-# Firewall ports to open
-ufw_allowed_ports:
-  - { port: 22, proto: tcp }  # SSH
-  - { port: 80, proto: tcp }  # HTTP
-  - { port: 443, proto: tcp } # HTTPS
-```
-```yaml
-# ansible/roles/docker/defaults/main.yml
----
-# Docker Standardvariablen
-docker_version: "latest"
-docker_compose_version: "2.21.0"
-docker_users: ["{{ ansible_user }}"]
-```
-```yaml
-# ansible/roles/nginx/defaults/main.yml
----
-# NGINX Standardvariablen
-nginx_worker_processes: auto
-nginx_worker_connections: 1024
-nginx_client_max_body_size: "100M"
-```
-```yaml
-# ansible/vars/defaults/main.yml
----
-# Domain-Konfiguration
-base_domain: "example.com"
-ssl_email: "admin@example.com"
-
-# Aktivierte Services
-services:
-  keycloak: true
-  nextcloud: true
-  paperless: true
-  nodered: true
-
-# Ports
-keycloak_port: 8080
-nextcloud_port: 8081
-paperless_port: 8000
-nodered_port: 1880
-
-# Docker-Konfiguration
-docker_compose_version: "2.21.0"
-```
-## Deployment Flow
-1. Common Role: Systemvorbereitung
-2. Docker Role: Container-Runtime
-3. NGINX Role: Reverse Proxy
-4. Services Role: Anwendungen
-
-## Wichtige Befehle
-```bash
-# Staging Deployment
-ansible-playbook -i inventory/staging site.yml
-
-# Production Deployment
-ansible-playbook -i inventory/production site.yml
-```
-
-## Sicherheitsaspekte
-- Automatische Passwortverwaltung
-- SSL/TLS-Konfiguration
-- Firewall-Einstellungen
-- Fail2ban-Integration
-
-## Entwicklungshinweise
-- Lokales Testing über WSL
-- Staging-Umgebung für Tests
-- Produktionsumgebung für finale Deployments
-
-## Updates und Wartung
-- Regelmäßige Updates über Ansible
-- Backup-Integration
-- Monitoring-Setup
-```
-```bash
-#!/bin/bash
-set -e
-
-# Ensure we're in the project root directory
-PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
-
-# Define directories relative to project root
-CREDENTIALS_DIR="${PROJECT_ROOT}/config/credentials"
-DOCKER_DIR="${PROJECT_ROOT}/docker"
-KEYCLOAK_SETUP_DIR="${PROJECT_ROOT}/scripts/setup/keycloak"
-ANSIBLE_PLAYBOOK="${PROJECT_ROOT}/ansible/site.yml"
-ANSIBLE_INVENTORY="${PROJECT_ROOT}/ansible/inventory/staging/hosts"
-NEXTCLOUD_DATA_DIR="${PROJECT_ROOT}/data/nextcloud/data"
-TEMP_FILE=$(mktemp)
-KEYCLOAK_DB_DIR="${PROJECT_ROOT}/data/keycloak-db"
-
-# Create necessary directories
-sudo mkdir -p "${CREDENTIALS_DIR}"
-sudo mkdir -p "${DOCKER_DIR}"
-sudo mkdir -p "${KEYCLOAK_SETUP_DIR}"
-
-# Initialize password variables
-KEYCLOAK_ADMIN_PASSWORD=""
-KC_DB_PASSWORD=""
-TESTADMIN_PASSWORD=""
-TESTUSER_PASSWORD=""
-TESTSERVICEUSER_PASSWORD=""
-KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=""
-
-# Function to read a password from a .env file
-read_password_from_env() {
-    local env_file="$1"
-    local variable_name="$2"
-    if [ -f "$env_file" ]; then
-        grep "^${variable_name}=" "$env_file" | cut -d '=' -f2
-    fi
-}
-
-# Function to generate secure passwords
-generate_password() {
-    openssl rand -base64 32
-}
-
-# Function to generate password if empty
-generate_password_if_empty() {
-    local variable_name="$1"
-    eval "local value=\$$variable_name"
-    if [ -z "$value" ]; then
-        eval "$variable_name=\"$(generate_password)\""
-        echo ">>> Generiertes Passwort für: $variable_name"
-    fi
-}
-
-# Function to create .env file
-create_env_file() {
-    local env_file="$1"
-    local content="$2"
-    if [ ! -f "$env_file" ]; then
-        echo "$content" > "$env_file"
-        echo ">>> .env file created: $env_file"
-    else
-        echo ">>> .env file already exists: $env_file"
-    fi
-}
-
-echo ">>> Überprüfe bestehende .env Dateien und lese Passwörter..."
-
-# Try reading passwords from existing .env files
-if [ -f "$DOCKER_DIR/.env" ]; then
-    KC_DB_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KC_DB_PASSWORD")
-    KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD")
-fi
-
-if [ -f "$KEYCLOAK_SETUP_DIR/.env" ]; then
-    KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD") # Überschreibt ggf. den Wert aus docker/.env
-    TESTADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTADMIN_PASSWORD")
-    TESTUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTUSER_PASSWORD")
-    TESTSERVICEUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTSERVICEUSER_PASSWORD")
-    KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_NEXTCLOUD_CLIENT_SECRET")
-fi
-
-echo ">>> Generiere neue Passwörter für fehlende Werte..."
-
-# Generate passwords if they are still empty
-generate_password_if_empty KEYCLOAK_ADMIN_PASSWORD
-generate_password_if_empty KC_DB_PASSWORD
-generate_password_if_empty TESTADMIN_PASSWORD
-generate_password_if_empty TESTUSER_PASSWORD
-generate_password_if_empty TESTSERVICEUSER_PASSWORD
-generate_password_if_empty KEYCLOAK_NEXTCLOUD_CLIENT_SECRET
-
-# Date for documentation
-SETUP_DATE=$(date '+%Y-%m-%d_%H-%M-%S')
-
-# Create credentials content
-CREDENTIALS_CONTENT=$(cat <<EOL
-Setup Date: ${SETUP_DATE}
-
-Keycloak Admin Credentials:
-Username: admin
-Password: ${KEYCLOAK_ADMIN_PASSWORD}
-
-Keycloak Database Credentials:
-Username: keycloak
-Password: ${KC_DB_PASSWORD}
-
-Test User Credentials:
-Admin Password: ${TESTADMIN_PASSWORD}
-User Password: ${TESTUSER_PASSWORD}
-Service User Password: ${TESTSERVICEUSER_PASSWORD}
-Nextcloud Client Secret: ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}
-
-EOL
-)
-
-# Store credentials hash
-CREDENTIALS_HASH=$(echo "$CREDENTIALS_CONTENT" | sha256sum | awk '{print $1}')
-echo "$CREDENTIALS_HASH" > "${CREDENTIALS_DIR}/credentials_hash.txt"
-echo ">>> Credentials hash stored in: ${CREDENTIALS_DIR}/credentials_hash.txt"
-
-# Set GPG PASSPHRASE
-export GPG_PASSPHRASE=$(generate_password)
-# Set GPG agent environment variable
-export GPG_TTY=$(tty)
-
-echo ">>> Trying openssl encryption first"
-# Alternative Verschlüsselung mit Openssl
-echo "$CREDENTIALS_CONTENT" > "$TEMP_FILE"
-          if openssl enc -aes-256-cbc -pbkdf2 -salt -in "$TEMP_FILE" -out "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" -k "$GPG_PASSPHRASE" ; then
-             echo ">>> Credentials encrypted successfully using openssl"
-             mv  "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
-        else
-           echo ">>> Openssl encryption failed, trying gpg"
-
-          # Attempt to kill existing gpg agent
-          gpgconf --kill gpg-agent 2>/dev/null
-          echo ">>> Attempting to manually start gpg-agent with pinentry-curses"
-          gpg-agent --daemon --pinentry-program /usr/bin/pinentry-curses
-          gpg-connect-agent /bye 2>/dev/null
-          eval $(gpg-agent --daemon)
-          gpg-connect-agent updatestartuptty /bye 2>/dev/null
-
-          # Attempt to encrypt credentials using GPG with error handling
-          if echo "$CREDENTIALS_CONTENT" | gpg --symmetric --cipher-algo AES256 -vvv -o "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg" ; then
-                echo ">>> Credentials encrypted successfully using gpg."
-          else
-             echo
-
-
-
-
-
-
-             ```
+diff --git a/.gitignore b/.gitignore
+index 8994b5d..a054b2f 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -1,3 +1,4 @@
+ data/
+ config/credentials
+ config/nextcloud/
++scripts/setup/paperless/node_modules
+\ No newline at end of file
+diff --git a/ansible/roles/services/defaults/main.yml b/ansible/roles/services/defaults/main.yml
+index 3555dd9..168ea0f 100644
+--- a/ansible/roles/services/defaults/main.yml
++++ b/ansible/roles/services/defaults/main.yml
+@@ -20,4 +20,13 @@ sso_config:
+         nextcloud-youpi: "youpi"
+ 
+ # Default paths and settings
+-nextcloud_data_dir: "/var/www/html/data"
+\ No newline at end of file
++nextcloud_data_dir: "/var/www/html/data"
++
++# ansible/roles/services/defaults/main.yml
++paperless_oidc:
++  client_id: paperless
++  provider_url: "https://{{ keycloak_host }}"
++  realm: "{{ keycloak_realm }}"
++  sign_algo: "RS256"
++  verify_ssl: false
++  scopes: "openid profile email"
+\ No newline at end of file
+diff --git a/ansible/roles/services/tasks/main.yml b/ansible/roles/services/tasks/main.yml
+index c6f13f1..c64d421 100644
+--- a/ansible/roles/services/tasks/main.yml
++++ b/ansible/roles/services/tasks/main.yml
+@@ -120,4 +120,15 @@
+ 
+ - name: "Display SSO configuration"
+   debug:
+-    var: sso_config_verification.stdout
+\ No newline at end of file
++    var: sso_config_verification.stdout
++
++# ansible/roles/services/tasks/main.yml
++- name: Configure Paperless
++  block:
++    - name: Setup Paperless Django settings
++      template:
++        src: paperless_django_settings.j2
++        dest: "{{ paperless_config_dir }}/django/settings.py"
++      tags: 
++        - paperless
++        - paperless-config
+\ No newline at end of file
+diff --git a/ansible/vars/defaults/main.yml b/ansible/vars/defaults/main.yml
+index 93934a6..e14a77f 100644
+--- a/ansible/vars/defaults/main.yml
++++ b/ansible/vars/defaults/main.yml
+@@ -19,3 +19,9 @@ nodered_port: 1880
+ 
+ # Docker-Konfiguration
+ docker_compose_version: "2.21.0"
++
++# Paperless Variables
++paperless_base_dir: /path/to/your/paperless
++paperless_oidc_client_id: paperless
++keycloak_host: auth.mrx8086.com
++keycloak_realm: office-automation
+\ No newline at end of file
+diff --git a/config/nginx/sites-available/keycloak b/config/nginx/sites-available/keycloak
+index cf437a2..a24450e 100644
+--- a/config/nginx/sites-available/keycloak
++++ b/config/nginx/sites-available/keycloak
+@@ -1,5 +1,5 @@
+ upstream keycloak_upstream {
+-    server 172.18.0.3:8080;
++    server 172.19.0.3:8080;
+ }
+ 
+ server {
+diff --git a/config/nginx/sites-available/nextcloud b/config/nginx/sites-available/nextcloud
+index 8357df3..3c24334 100644
+--- a/config/nginx/sites-available/nextcloud
++++ b/config/nginx/sites-available/nextcloud
+@@ -1,5 +1,5 @@
+ upstream nextcloud_upstream {
+-    server 172.19.0.3:80;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP IST
++    server 172.20.0.3:80;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP IST
+ }
+ 
+ server {
+diff --git a/config/nginx/sites-available/paperless b/config/nginx/sites-available/paperless
+index 6a7b80c..41563c5 100644
+--- a/config/nginx/sites-available/paperless
++++ b/config/nginx/sites-available/paperless
+@@ -1,41 +1,61 @@
+-# HTTP-Weiterleitung auf HTTPS
++upstream paperless_upstream {
++    server 172.18.0.4:8000;  # SICHERSTELLEN, DASS DIES DIE KORREKTE IP UND DER PORT IST
++}
++
+ server {
+     listen 80;
+     server_name docs.mrx8086.com;
+-
+-    # Weiterleitung von HTTP zu HTTPS
+     return 301 https://$host$request_uri;
+ }
+ 
+-# HTTPS-Server
+ server {
+     listen 443 ssl;
+     server_name docs.mrx8086.com;
+ 
+-    # SSL-Zertifikate einbinden
++    # SSL Configuration
+     ssl_certificate /etc/nginx/ssl/mrx8086.com/fullchain.pem;
+     ssl_certificate_key /etc/nginx/ssl/mrx8086.com/privkey.pem;
+ 
+-    # Empfohlene SSL-Einstellungen (optional)
+     ssl_protocols TLSv1.2 TLSv1.3;
+     ssl_prefer_server_ciphers on;
+-    ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
+-    ssl_session_cache shared:SSL:10m;
+-    ssl_session_timeout 10m;
++    ssl_ciphers 'TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305';
++    ssl_session_timeout 1d;
++    ssl_session_cache shared:MozSSL:10m;
++    ssl_session_tickets off;
+ 
++    # Security headers
++    add_header X-Content-Type-Options nosniff always;
++    add_header X-XSS-Protection "1; mode=block" always;
++    add_header X-Frame-Options SAMEORIGIN always;
+     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
+-    add_header X-Content-Type-Options nosniff;
+-    add_header X-Frame-Options DENY;
+-    add_header X-XSS-Protection "1; mode=block";
++    add_header Content-Security-Policy "frame-ancestors 'self'; default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; media-src 'self';" always;
++
++    # Proxy settings
++    proxy_set_header X-Real-IP $remote_addr;
++    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
++    proxy_set_header X-Forwarded-Proto $scheme;
++    proxy_set_header X-Forwarded-Host $host;
++    proxy_set_header X-Forwarded-Port 443;
++    proxy_set_header Host $host;
++    proxy_http_version 1.1;
+ 
+-    # Paperless-NGX Konfiguration
++    # Paperless specific settings
++    client_max_body_size 512M;
++    fastcgi_buffers 64 4K;
++
++    # Root location
+     location / {
+-        proxy_pass http://127.0.0.1:8000;  # Paperless läuft auf Port 8000 innerhalb des Docker-Containers
+-        proxy_set_header Host $host;
+-        proxy_set_header X-Real-IP $remote_addr;
+-        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+-        proxy_set_header X-Forwarded-Proto https;
+-        proxy_set_header X-Forwarded-Port 443;
++        proxy_pass http://paperless_upstream;
++        proxy_set_header Upgrade $http_upgrade;
++        proxy_set_header Connection "upgrade";
++        proxy_connect_timeout 60s;
++        proxy_send_timeout 60s;
++        proxy_read_timeout 60s;
+     }
+-}
+ 
++    # Deny access to hidden files
++    location ~ /\. {
++        deny all;
++        return 404;
++    }
++}
+\ No newline at end of file
+diff --git a/docker/.env b/docker/.env
+index 2a7c926..0993b0b 100644
+--- a/docker/.env
++++ b/docker/.env
+@@ -11,4 +11,49 @@ NEXTCLOUD_DB_USER=nextcloud
+ NEXTCLOUD_DB_PASSWORD=YeTn4f1IIM9a7I3Q7oZNaEhs
+ NEXTCLOUD_DB_ROOT_PASSWORD=rY26aXw9uMOqz2BjtevQ4oKB
+ NEXTCLOUD_ADMIN_USER=admin
+-NEXTCLOUD_ADMIN_PASSWORD=jTjRBEJb2ZSAH0iJoqeZijYL
+\ No newline at end of file
++NEXTCLOUD_ADMIN_PASSWORD=jTjRBEJb2ZSAH0iJoqeZijYL
++
++
++
++# ==============================================================================
++# Paperless Environment Variables
++# ==============================================================================
++
++# Datenbank-Konfiguration
++# ------------------------------------------------------------------------------
++# Benutzername für die Paperless-Datenbank
++PAPERLESS_DB_USER=paperless
++
++# Passwort für die Paperless-Datenbank
++PAPERLESS_DB_PASSWORD=sq812ylB1Lfk49xbP8xxNSDA
++
++# Datenbank Name
++PAPERLESS_DB_NAME=paperless
++
++# Paperless Admin User
++# ------------------------------------------------------------------------------
++# Benutzername für den Paperless Admin Account
++PAPERLESS_ADMIN_USER=admin
++
++# Passwort für den Paperless Admin Account
++PAPERLESS_ADMIN_PASSWORD=GRnrM1lrMl63E16HgZk8PBXU
++
++# Paperless Secret Key
++# ------------------------------------------------------------------------------
++# Geheimer Schlüssel für Paperless (wird für Django benötigt)
++# Sollte ein zufälliger, sicherer String sein
++PAPERLESS_SECRET_KEY=qfQ7MeGB79F6nbTgFk99K2Nx
++
++# Paperless OpenID Connect (Keycloak) Konfiguration
++# ------------------------------------------------------------------------------
++# Client ID für Paperless in Keycloak
++PAPERLESS_CLIENT_ID=paperless
++
++# Client Secret für Paperless in Keycloak
++PAPERLESS_CLIENT_SECRET=CSbw9ldbZBUGGQSJoAUEg10QKgjdb6Tq
++
++# Die URL von Paperless
++PAPERLESS_URL=https://docs.mrx8086.com
++
++# Erlaubte Hosts für Paperless
++PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com
+\ No newline at end of file
+diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
+index ccbcd3b..d3bf016 100644
+--- a/docker/docker-compose.yml
++++ b/docker/docker-compose.yml
+@@ -117,8 +117,102 @@ services:
+     networks:
+       - nextcloud-network
+ 
++  paperless:
++    image: ghcr.io/paperless-ngx/paperless-ngx:latest
++    container_name: paperless
++    restart: unless-stopped
++    ports:
++      - "8000:8000"
++    volumes:
++      - ../data/paperless:/usr/src/paperless/data
++      - ../config/paperless/media:/usr/src/paperless/media
++      - ../config/paperless/export:/usr/src/paperless/export
++      - ../config/paperless/consume:/usr/src/paperless/consume
++    environment:
++      # Basis-Konfiguration
++      - PAPERLESS_ADMIN_USER=${PAPERLESS_ADMIN_USER}
++      - PAPERLESS_ADMIN_PASSWORD=${PAPERLESS_ADMIN_PASSWORD}
++      - PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY}
++      - PAPERLESS_URL=https://docs.mrx8086.com
++      - PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com
++      - PAPERLESS_REDIS=redis://paperless-redis:6379
++      - PAPERLESS_LOGGING_DIR=/dev/stdout
++      - PAPERLESS_LOGGING_LEVEL=DEBUG
++      - DJANGO_LOG_LEVEL=DEBUG
++      
++      # OIDC Basis-Einstellungen
++      - PAPERLESS_ENABLE_OIDC=true
++      - PAPERLESS_OIDC_RP_PROVIDER_URL=https://auth.mrx8086.com/realms/office-automation
++      - PAPERLESS_OIDC_RP_CLIENT_ID=paperless
++      - PAPERLESS_OIDC_RP_CLIENT_SECRET=${PAPERLESS_CLIENT_SECRET}
++      
++      # OIDC Endpoints
++      - PAPERLESS_OIDC_AUTH_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/auth
++      - PAPERLESS_OIDC_TOKEN_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/token
++      - PAPERLESS_OIDC_USERINFO_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/userinfo
++      - PAPERLESS_OIDC_JWKS_ENDPOINT=https://auth.mrx8086.com/realms/office-automation/protocol/openid-connect/certs
++      
++      # OIDC Claims und Scopes
++      - PAPERLESS_OIDC_RP_SCOPE=openid profile email
++      - PAPERLESS_OIDC_RP_USERNAME_CLAIM=preferred_username
++      - PAPERLESS_OIDC_RP_NAME_CLAIM=name
++      - PAPERLESS_OIDC_RP_EMAIL_CLAIM=email
++      
++      # OIDC Sicherheitseinstellungen
++      - PAPERLESS_OIDC_RP_SIGN_ALGO=RS256
++      - PAPERLESS_OIDC_RP_VERIFY_SSL=false
++      - PAPERLESS_OIDC_USE_PKCE=true
++      
++      # OIDC Token-Management
++      - PAPERLESS_OIDC_RP_RENEW_TOKEN_BEFORE_EXPIRY=true
++    
++    depends_on:
++      - paperless-db
++      - paperless-redis
++    networks:
++      - paperless-network
++    extra_hosts:
++      - "auth.mrx8086.com:172.23.171.133"
++    healthcheck:
++      test: ["CMD", "curl", "-f", "http://localhost:8000/"]
++      interval: 30s
++      timeout: 10s
++      retries: 3
++
++  paperless-db:
++    image: postgres:15
++    container_name: paperless-db
++    restart: unless-stopped
++    environment:
++      POSTGRES_USER: ${PAPERLESS_DB_USER}
++      POSTGRES_PASSWORD: ${PAPERLESS_DB_PASSWORD}
++      POSTGRES_DB: paperless
++    volumes:
++      - ../data/paperless-db:/var/lib/postgresql/data
++    networks:
++      - paperless-network
++    healthcheck:
++      test: ["CMD-SHELL", "pg_isready -U ${PAPERLESS_DB_USER} -d paperless"]
++      interval: 10s
++      timeout: 5s
++      retries: 5
++  
++  paperless-redis:
++    image: redis:7
++    container_name: paperless-redis
++    restart: unless-stopped
++    networks:
++      - paperless-network
++    healthcheck:
++      test: ["CMD", "redis-cli", "ping"]
++      interval: 10s
++      timeout: 5s
++      retries: 5
++
+ networks:
+   keycloak-network:
+     driver: bridge
+   nextcloud-network:
++    driver: bridge
++  paperless-network:
+     driver: bridge
+\ No newline at end of file
+diff --git a/docs/context/configuration/docker-compose.yml b/docs/context/configuration/docker-compose.yml
+index 86b29d1..d36b088 100644
+--- a/docs/context/configuration/docker-compose.yml
++++ b/docs/context/configuration/docker-compose.yml
+@@ -100,8 +100,66 @@ services:
+     networks:
+       - nextcloud-network
+ 
++  paperless:
++    image: ghcr.io/paperless-ngx/paperless-ngx:latest
++    container_name: paperless
++    restart: unless-stopped
++    ports:
++      - "8000:8000"
++    volumes:
++      - ../data/paperless:/usr/src/paperless/data
++      - ../config/paperless/media:/usr/src/paperless/media
++      - ../config/paperless/export:/usr/src/paperless/export
++      - ../config/paperless/consume:/usr/src/paperless/consume
++    environment:
++      - PAPERLESS_ADMIN_USER=${PAPERLESS_ADMIN_USER}
++      - PAPERLESS_ADMIN_PASSWORD=${PAPERLESS_ADMIN_PASSWORD}
++      - PAPERLESS_SECRET_KEY=${PAPERLESS_SECRET_KEY}
++      - PAPERLESS_URL=https://docs.mrx8086.com
++      - PAPERLESS_ALLOWED_HOSTS=docs.mrx8086.com
++      - PAPERLESS_ENABLE_OIDC=true
++      - PAPERLESS_OIDC_RP_CLIENT_ID=${PAPERLESS_CLIENT_ID}
++      - PAPERLESS_OIDC_RP_CLIENT_SECRET=${PAPERLESS_CLIENT_SECRET}
++      - PAPERLESS_OIDC_RP_PROVIDER_URL=https://auth.mrx8086.com/realms/office-automation
++      - PAPERLESS_OIDC_RP_USERNAME_CLAIM=preferred_username
++      - PAPERLESS_OIDC_RP_NAME_CLAIM=name
++      - PAPERLESS_OIDC_RP_EMAIL_CLAIM=email
++      - PAPERLESS_OIDC_RP_RENEW_TOKEN_BEFORE_EXPIRY=true
++      - PAPERLESS_OIDC_RP_VERIFY_SSL=false
++    depends_on:
++      - paperless-db
++    networks:
++      - paperless-network
++    extra_hosts:
++      - "auth.mrx8086.com:172.23.171.133"
++    healthcheck:
++      test: ["CMD", "curl", "-f", "http://localhost:8000/"]
++      interval: 30s
++      timeout: 10s
++      retries: 3
++
++  paperless-db:
++    image: postgres:15
++    container_name: paperless-db
++    restart: unless-stopped
++    environment:
++      POSTGRES_USER: ${PAPERLESS_DB_USER}
++      POSTGRES_PASSWORD: ${PAPERLESS_DB_PASSWORD}
++      POSTGRES_DB: paperless
++    volumes:
++      - ../data/paperless-db:/var/lib/postgresql/data
++    networks:
++      - paperless-network
++    healthcheck:
++      test: ["CMD-SHELL", "pg_isready -U ${PAPERLESS_DB_USER} -d paperless"]
++      interval: 10s
++      timeout: 5s
++      retries: 5
++
+ networks:
+   keycloak-network:
+     driver: bridge
+   nextcloud-network:
++    driver: bridge
++  paperless-network:
+     driver: bridge
+\ No newline at end of file
+diff --git a/git_diff.txt b/git_diff.txt
+index bfb2d94..2f87fcb 100644
+--- a/git_diff.txt
++++ b/git_diff.txt
+@@ -1,823 +0,0 @@
+-Vielen Dank für die Bereitstellung der Dateien. Ich habe alle notwendigen Informationen, um die Dokumentation zu erstellen. Hier ist der Inhalt der finalen Dokumentationsdateien:
+-
+-```markdown
+-# Automatisiertes Büro 2.0 - Projektdokumentation
+-
+-## Inhaltsverzeichnis
+-1.  [Projektübersicht](#projektübersicht)
+-2.  [Systemarchitektur](#systemarchitektur)
+-3.  [Entwicklungsumgebung](#entwicklungsumgebung)
+-4.  [Konfigurationen](#konfigurationen)
+-5.  [Installationsanleitung](#installationsanleitung)
+-6.  [Workflows](#workflows)
+-7.  [Sicherheitskonzept](#sicherheitskonzept)
+-8.  [Wartung und Monitoring](#wartung-und-monitoring)
+-9.  [Troubleshooting](#troubleshooting)
+-
+-## Projektübersicht
+-
+-### Projektziele
+-- Vollständige Automatisierung administrativer und kaufmännischer Prozesse
+-- Kostensenkung durch lokale Open-Source-Lösungen
+-- Unabhängigkeit von externen Diensten
+-- Zentralisierte Verwaltung aller Geschäftsprozesse
+-
+-### Projektumfang
+-- Integration aller Kommunikationskanäle
+-- Automatisierte Dokumentenverarbeitung
+-- Prozessautomatisierung
+-- Zentrale Authentifizierung
+-- KI-gestützte Korrespondenz
+-
+-#### Keycloak-Rolle
+-Keycloak spielt eine zentrale Rolle als Authentifizierungsstelle. Es stellt die Single-Sign-On (SSO) Funktionalität für alle Dienste der zentralen Plattform bereit und sichert somit den Zugriff auf die verschiedenen Anwendungen.
+-
+-## Systemarchitektur
+-
+-#### Architekturübersicht
+-
+-```mermaid
+-graph TB
+-    subgraph Eingangssysteme
+-        Email[E-Mail]
+-        WhatsApp[WhatsApp]
+-        Post[Physische Post]
+-        Teams[Teams/Webex]
+-    end
+-
+-    subgraph Zentrale_Plattform
+-        NC[Nextcloud - Dokumentenverwaltung]
+-        PL[Paperless - Dokumentenmanagement]
+-        NR[Node-RED - Prozessautomatisierung]
+-        KC[Keycloak - SSO]
+-        OUI[OpenWebUI - KI-Korrespondenz]
+-		KI[Kimai - Zeiterfassung]
+-    end
+-
+-    subgraph Monitoring_Analytics
+-        ELK[ELK Stack - Logging & Analyse]
+-    end
+-
+-    subgraph Geschäftsprozesse
+-        TP[Task-Priorisierung]
+-        subgraph Finanzen
+-            RE[Rechnungserstellung]
+-            ZA[Zahlungsabwicklung]
+-            BA[Banken-API]
+-        end
+-        subgraph Verwaltung
+-            KV[Kundenverwaltung]
+-            ZE[Zeiterfassung]
+-            DO[Dokumentenarchiv]
+-        end
+-    end
+-
+-    Email --> NC
+-    WhatsApp --> NC
+-    Post --> PL
+-    Teams --> NC
+-
+-    NC --> NR
+-    PL --> NR
+-    NR --> TP
+-	KI --> TP
+-
+-    TP --> RE
+-    TP --> ZA
+-    TP --> KV
+-    TP --> ZE
+-    TP --> DO
+-
+-    ZA <--> BA
+-
+-    KC -.->|Authentifizierung| NC
+-    KC -.->|Authentifizierung| PL
+-    KC -.->|Authentifizierung| NR
+-    KC -.->|Authentifizierung| OUI
+-	KC -.->|Authentifizierung| KI
+-
+-    NR --> ELK
+-    OUI --> NR
+-
+-    classDef container fill:#e1f5fe,stroke:#01579b
+-    classDef process fill:#e8f5e9,stroke:#2e7d32
+-    classDef auth fill:#fff3e0,stroke:#ef6c00
+-    classDef monitoring fill:#fce4ec,stroke:#c2185b
+-
+-    class NC,PL,NR,KI container
+-    class TP,RE,ZA,KV,ZE,DO process
+-    class KC auth
+-    class ELK monitoring
+-```
+-
+-#### Beschreibung der Architekturkomponenten
+-
+-Die Systemarchitektur ist in vier Hauptbereiche gegliedert:
+-
+-1.  **Eingangssysteme:**
+-    - Erfassen verschiedene Kommunikationskanäle zentral.
+-    - Sorgen für eine einheitliche Weiterverarbeitung aller Eingänge.
+-
+-2.  **Zentrale Plattform:**
+-    - **Nextcloud (NC):** Dient als zentraler Hub für die Dateiverwaltung und Kollaboration.
+-    - **Paperless (PL):** Zuständig für das Dokumentenmanagement und die optische Zeichenerkennung (OCR).
+-    - **Node-RED (NR):** Automatisierung von Workflows und Geschäftsprozessen.
+-    - **Keycloak (KC):** Bereitstellung von Single-Sign-On (SSO) und Identitätsmanagement.
+-        - Keycloak wird als zentrale Authentifizierungsstelle für alle Dienste der zentralen Plattform verwendet, wodurch ein sicherer und zentralisierter Zugriff gewährleistet wird.
+-    - **OpenWebUI (OUI):** KI-gestützte Kommunikation und Integration in die Workflow-Automatisierung
+-    - **Kimai (KI):** Zeiterfassungslösung zur Verwaltung von Arbeitszeiten und Projekten.
+-
+-3.  **Geschäftsprozesse:**
+-    - Automatisierte Task-Priorisierung (TP) für eine effiziente Aufgabenverteilung.
+-    - Integrierte Finanzprozesse mit Bankenanbindung (RE, ZA, BA).
+-    - Zentralisierte Verwaltungsprozesse (KV, ZE, DO).
+-
+-4.  **Monitoring & Analytics:**
+-    - **ELK Stack (ELK):** Ermöglicht umfassendes Logging und Analyse in Echtzeit zur Überwachung aller Systeme.
+-
+-#### Containerstruktur
+-- Docker als Containerisierungsplattform
+-- Microservices-Architektur
+-- Interne Netzwerkkonfiguration
+-
+-### Komponenten
+-#### Nextcloud
+-- Funktion: Zentrale Dateiverwaltung und Kollaboration
+-- Version: `[VERSION]`
+-- Besondere Konfigurationen:
+-  - [Wird ergänzt]
+-
+-#### Paperless
+-- Funktion: Dokumentenmanagement und OCR
+-- Version: `[VERSION]`
+-- Besondere Konfigurationen:
+-  - [Wird ergänzt]
+-
+-#### Keycloak
+-- Funktion: Single-Sign-On und Identitätsmanagement
+-- Version: `[VERSION]`
+-- Besondere Konfigurationen:
+-  - [Wird ergänzt]
+-
+-#### Node-RED
+-- Funktion: Workflow-Automatisierung
+-- Version: `[VERSION]`
+-- Implementierte Flows:
+-  - [Wird ergänzt]
+-
+-#### ELK Stack
+-- Funktion: Logging und Monitoring
+-- Version: `[VERSION]`
+-- Besondere Konfigurationen:
+-  - [Wird ergänzt]
+-
+-#### OpenWebUI
+-- Funktion: KI-gestützte Kommunikation
+-- Version: `[VERSION]`
+-- Integrationen:
+-  - [Wird ergänzt]
+-
+-#### Kimai
+-- Funktion: Zeiterfassung
+-- Version: `[VERSION]`
+-- Besondere Konfigurationen:
+-  - [Wird ergänzt]
+-
+-## Entwicklungsumgebung
+-
+-### Systemvoraussetzungen
+-- Windows mit WSL (Windows Subsystem for Linux)
+-- Visual Studio Code
+-- Docker Desktop
+-- NGINX Proxy Manager (läuft in WSL)
+-
+-#### Domain-Konfiguration
+-Die Entwicklungsumgebung nutzt die Domain `mrx8086.com` mit verschiedenen Subdomains für die einzelnen Services. Diese werden lokal über die Windows-Hosts-Datei (`C:\Windows\System32\drivers\etc\hosts`) aufgelöst.
+-
+-```plaintext
+-# Development Environment Host Entries
+-127.0.0.1 mrx8086.com
+-127.0.0.1 proxy.mrx8086.com     # NGINX Proxy Manager
+-172.23.171.133 auth.mrx8086.com # Keycloak
+-127.0.0.1 cloud.mrx8086.com     # Nextcloud
+-127.0.0.1 docs.mrx8086.com      # Paperless
+-127.0.0.1 time.mrx8086.com      # Kimai
+-127.0.0.1 automate.mrx8086.com  # n8n
+-```
+-
+-#### Service-Übersicht
+-| Subdomain | Service | Beschreibung |
+-|-----------|---------|--------------|
+-| proxy.mrx8086.com | NGINX Proxy Manager | Reverse Proxy und SSL-Management (lokal in der Development Umgebung) |
+-| auth.mrx8086.com | Keycloak | Zentrale Authentifizierung |
+-| cloud.mrx8086.com | Nextcloud | Dokumentenverwaltung |
+-| docs.mrx8086.com | Paperless | Dokumentenmanagement |
+-| time.mrx8086.com | Kimai | Zeiterfassung |
+-| automate.mrx8086.com | n8n | Workflow-Automatisierung |
+-
+-#### WSL-Konfiguration
+-- NGINX Proxy Manager läuft in WSL
+-- IP-Adresse des WSL-Systems: 172.23.171.133 (Beispiel, kann sich ändern)
+-- Alle Docker-Container werden innerhalb von WSL betrieben
+-
+-#### `setup_realm.js`
+-Dieses Skript wird verwendet, um den Keycloak-Realm, die zugehörigen Clients und Testbenutzer automatisiert zu erstellen. Es verwendet eine `.env`-Datei zur Konfiguration.
+-
+-#### Verwendung von .env
+-Die Konfigurationen für das setup_realm.js Script werden in einer .env Datei gespeichert. Die benötigten Umgebungsvariablen sind unten aufgelistet:
+-- `KEYCLOAK_URL`: Die URL zum Keycloak Server (z.B. https://auth.mrx8086.com)
+-- `KEYCLOAK_ADMIN_USER`: Der Benutzername des Keycloak Administrators (z.B. admin).
+-- `KEYCLOAK_ADMIN_PASSWORD`: Das Passwort des Keycloak Administrators.
+-- `NEXTCLOUD_CLIENT_ID`: Die Client ID für Nextcloud. (z.B. nextcloud)
+-- `PAPERLESS_CLIENT_ID`: Die Client ID für Paperless (z.B. paperless).
+-- `NODERED_CLIENT_ID`: Die Client ID für Node-RED (z.B. nodered).
+-- `TESTADMIN_PASSWORD`: Das Passwort für den Testadmin User.
+-- `TESTUSER_PASSWORD`: Das Passwort für den Testuser User.
+-- `TESTSERVICEUSER_PASSWORD`: Das Passwort für den Testserviceuser User.
+-- `KEYCLOAK_NEXTCLOUD_CLIENT_SECRET`: Das Client Secret für Nextcloud.
+-- `NEXTCLOUD_URL`: Die URL zur Nextcloud Instanz (z.B. https://cloud.mrx8086.com).
+-
+-#### NGINX-Konfigurationen
+-Für jeden Service existiert eine dedizierte NGINX-Konfiguration. In der Development Umgebung wird der **NGINX Proxy Manager** verwendet. Für **Staging** und **Production** werden die entsprechenden NGINX Konfigurationsdateien in `/config/nginx` abgelegt.
+-
+-## Konfigurationen
+-
+-### Netzwerkkonfiguration
+-- Interne Netzwerkstruktur (noch zu definieren)
+-- Reverse Proxy Konfiguration über den Nginx Proxy Manager in der Development Umgebung, und Nginx Server Config in Staging und Production.
+-- SSL/TLS-Setup: Selbsignierte Zertifikate in der Development Umgebung, Letsencrypt in Staging und Production.
+-- Konfigurationsdateien für NGINX Server Config sind unter `/config/nginx/sites-available/` zu finden.
+-- Für die Entwicklungsumgebung werden die Konfigurationen über den Nginx Proxy Manager konfiguriert.
+-- Die SSL Zertifikate für die Development Umgebung werden als selbsignierte Zertifikate generiert und in `/config/nginx/ssl/mrx8086.com/` abgelegt.
+-- In der Staging und Production Umgebung werden die Zertifikate über Let's Encrypt oder eine andere Zertifizierungsstelle verwaltet.
+-
+-#### Umgebungsvariablen
+-Es werden zwei `.env`-Dateien verwendet:
+-Eine im `docker/` Verzeichnis für die Docker-Konfiguration und eine im `scripts/setup/keycloak/` für das `setup_realm.js`-Skript.
+-
+-**`docker/.env`:**
+-```env
+-# Generated on 2024-12-12_18-12-36
+-# Keycloak Admin
+-KEYCLOAK_ADMIN_PASSWORD=9aD5Fddh457QqmvQqr6Rb8bu
+-
+-# Keycloak Database
+-KC_DB_USERNAME=keycloak
+-KC_DB_PASSWORD=p47616y763z101f3
+-```
+-
+-**`scripts/setup/keycloak/.env`:**
+-```env
+-KEYCLOAK_URL=https://auth.mrx8086.com
+-KEYCLOAK_ADMIN_USER=admin
+-KEYCLOAK_ADMIN_PASSWORD=9aD5Fddh457QqmvQqr6Rb8bu
+-NEXTCLOUD_CLIENT_ID=nextcloud
+-PAPERLESS_CLIENT_ID=paperless
+-NODERED_CLIENT_ID=nodered
+-TESTADMIN_PASSWORD=TestAdminPwd
+-TESTUSER_PASSWORD=TestUserPwd
+-TESTSERVICEUSER_PASSWORD=TestServiceUserPwd
+-KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=OSbJ08zyjBWChwBR7S6c1q4sU0d8zvEK
+-NEXTCLOUD_URL=https://cloud.mrx8086.com
+-```
+-
+-Die Passwörter in der `.env` Datei im `scripts/setup/keycloak` werden vom `setup_environment.sh` Skript generiert.
+-
+-#### Keycloak-Konfiguration
+-
+-Keycloak ist als zentrale Authentifizierungsstelle konfiguriert. Die Realm-Konfiguration, Clients und Benutzer werden über das `setup_realm.js` Skript definiert, die Konfiguration wird über die `.env` Datei im `/scripts/setup/keycloak` Verzeichnis angepasst.
+-
+-##### Realm-Konfiguration
+-- **Realm-Name:** `office-automation`
+-- **Anzeige Name:** `Office Automation`
+-- **SSL ist erforderlich**: `external`
+-- **Registrierung ist nicht erlaubt**: `false`
+-- **Login mit Email ist erlaubt**: `true`
+-- **Doppelte Email ist nicht erlaubt**: `false`
+-- **Passwort Reset ist erlaubt**: `true`
+-- **Username Bearbeitung ist nicht erlaubt**: `false`
+-- **Brute Force Schutz ist aktiviert**: `true`
+-- **Permanente Sperrung ist nicht aktiviert**: `false`
+-- **Standard Signature Algorithm**: `RS256`
+-- **WebAuthn Policy Signatur Algorithmen**: `ES256`
+-- **WebAuthn Policy Attestation Conveyance Preference**: `none`
+-- **WebAuthn Policy Authenticator Attachment**: `cross-platform`
+-- **WebAuthn Policy Require Resident Key**: `not specified`
+-- **WebAuthn Policy User Verification Requirement**: `preferred`
+-- **WebAuthn Policy Create Timeout**: `0`
+-- **WebAuthn Policy Avoid Same Authenticator Register**: `false`
+-- **Default Default Client Scopes**: `email`, `profile`, `roles`, `web-origins`
+-- **Default Optional Client Scopes**: `address`, `phone`, `offline_access`, `microprofile-jwt`
+-
+-##### Clients
+-Die folgenden Clients werden über das Skript konfiguriert:
+-- **Nextcloud:**
+-  -   **Client ID:** `nextcloud`
+-  -   **Name:** `Nextcloud`
+-   -   **Redirect URIs:**
+-        - `https://cloud.mrx8086.com/apps/sociallogin/custom_oidc/keycloak`
+-        - `https://cloud.mrx8086.com/apps/user_oidc/code`
+-    -   **Post Logout Redirect URIs:** `https://cloud.mrx8086.com/*`
+-- **Paperless:**
+-  -   **Client ID:** `paperless`
+-  -   **Name:** `Paperless`
+-  -   **Redirect URIs:** `https://docs.mrx8086.com/*`
+-- **Node-RED:**
+-  -   **Client ID:** `nodered`
+-  -   **Name:** `Node-RED`
+-  -   **Redirect URIs:** `https://automate.mrx8086.com/*`
+-
+-##### Gruppen
+-- **nextcloud-admins:** Gruppe für Nextcloud Benutzer mit Admin Rechten.
+-- **nextcloud-users:** Gruppe für reguläre Nextcloud Benutzer.
+-- **nextcloud-youpi:** Gruppe für Nextcloud Youpi Benutzer.
+-- **nextcloud-service:** Gruppe für Nextcloud Service Benutzer.
+-
+-##### Benutzer
+-- **testadmin:**
+-  - Benutzername: `testadmin`
+-  - Passwort: wird entweder aus der Umgebungsvariable `TESTADMIN_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
+-  - Gruppen: `nextcloud-admins`,`nextcloud-users`
+-- **testuser:**
+-  - Benutzername: `testuser`
+-  - Passwort: wird entweder aus der Umgebungsvariable `TESTUSER_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
+-  - Gruppen: `nextcloud-users`,`nextcloud-youpi`
+-- **testserviceuser:**
+-    - Benutzername: `testserviceuser`
+-    - Passwort: wird entweder aus der Umgebungsvariable `TESTSERVICEUSER_PASSWORD` gelesen oder standardmäßig `initial123!` gesetzt.
+-    - Gruppen: `nextcloud-service`
+-
+-#### SSL/TLS-Setup
+--   **Entwicklungsumgebung (`dev`):** Für lokale Entwicklung werden selbsignierte SSL-Zertifikate verwendet.
+--   **Staging/Produktionsumgebung (`staging`, `production`):** Hier werden SSL-Zertifikate über Let's Encrypt oder eine ähnliche Zertifizierungsstelle verwaltet.
+-
+-## Installationsanleitung
+-#### Voraussetzungen
+-- Docker Version: `[VERSION]`
+-- Minimal Systemanforderungen:
+-  - CPU: `[ANFORDERUNG]`
+-  - RAM: `[ANFORDERUNG]`
+-  - Speicher: `[ANFORDERUNG]`
+-- Für die Ausführung des `setup_realm.js` Skriptes wird `Node.js` benötigt
+-- Die genaue Version von `Node.js` wird zu einem späteren Zeitpunkt dokumentiert.
+-- Vor dem starten müssen die Passwörter generiert und die `.env` Dateien erstellt werden. Hierzu wird das `setup_environment.sh` verwendet. Dieses Skript sollte **nicht in der Produktionsumgebung** verwendet werden.
+-- Das Skript erstellt die benötigten Verzeichnisse, generiert zufällige Passwörter, speichert diese verschlüsselt ab, und erstellt die benötigten `.env` Dateien.
+-- Für die Ausführung des `setup_realm.js` Skriptes wird `Node.js` und `npm` benötigt
+-- Die benötigten Node Module `dotenv` und `axios` können mit `npm install dotenv axios` installiert werden.
+-- Die `.env` Dateien werden im `/docker` und im `/scripts/setup/keycloak` Verzeichnis abgelegt.
+-
+-#### Keycloak-Installation
+-1.  Führe das `setup_environment.sh` Skript aus, um die .env Dateien, die Passwörter zu generieren und die Credentials zu verschlüsseln.
+-2.  Kopiere die `docker-compose.yml` Datei in das `docker/` Verzeichnis.
+-3.  Kopiere die `.env` Datei in das `docker/` Verzeichnis.
+-4.  Führe `docker-compose up -d` im `docker/` Verzeichnis aus um Keycloak zu starten.
+-
+-#### Ausführen von `setup_realm.js`
+-1.  Stelle sicher, dass Node.js und npm installiert sind.
+-2.  Wechsle in das `/scripts/setup/keycloak` Verzeichnis.
+-3.  Installiere die benötigten npm Pakete mit `npm install dotenv axios`.
+-4.  Führe das Skript mit `node setup_realm.js` aus. Dies erstellt den Keycloak-Realm, die Clients und die Testbenutzer.
+-    * Das Script befindet sich im `/scripts/setup/keycloak` Verzeichnis
+-
+-## Workflows
+-#### Dokumentenverarbeitung
+-- Eingangsverarbeitung
+-- OCR-Prozess
+-- Kategorisierung
+-- Archivierung
+-
+-#### Geschäftsprozesse
+-- Rechnungsstellung
+-- Zahlungsabwicklung
+-- Kundenmanagement
+-- Zeiterfassung
+-
+-#### Authentifizierungsflow
+-Die Authentifizierung der Benutzer für alle Dienste wird über Keycloak abgewickelt. Details zu den Authentifizierungsabläufen werden in einem späteren Schritt dokumentiert.
+-
+-## Sicherheitskonzept
+-#### Zugriffsmanagement
+-- Rollenkonzept (wird in späteren schritten dokumentiert)
+-- Berechtigungsmatrix (wird in späteren schritten dokumentiert)
+-- Authentifizierungsflows (siehe Workflows)
+-- Keycloak wird als zentrale Authentifizierungsstelle verwendet, Passwortrichtlinien werden in Keycloak definiert.
+-
+-#### Datensicherheit
+-- Verschlüsselung (wird in späteren schritten dokumentiert)
+-- Backup-Strategie (wird in späteren schritten dokumentiert)
+-- Notfallwiederherstellung (wird in späteren schritten dokumentiert)
+-
+-## Wartung und Monitoring
+-#### Regelmäßige Wartungsaufgaben
+-- Backup-Überprüfung
+-- Updates
+-- Performance-Monitoring
+-
+-Details zur Wartung und dem Monitoring werden in späteren Schritten dokumentiert.
+-
+-## Troubleshooting
+-#### Bekannte Probleme
+-- [Wird ergänzt mit auftretenden Problemen]
+-
+-#### Debugging
+-- Log-Analyse
+-- Fehlerbehandlung
+-- Support-Prozesse
+-Details zu bekannten Problemen und zur Fehlerbehandlung werden in späteren Schritten dokumentiert.
+-```
+-```markdown
+-# Automated Office 2.0 - Current Project State
+-
+-## Overview
+-Project to automate all administrative and commercial processes within the company, using open-source solutions.
+-
+-## Current Implementation Status
+-
+-### 1. Project Structure
+-- Basic directory structure created
+-- Ansible roles established (common, docker, nginx, services)
+-- Configuration directories set up for all services
+-- Documentation structure established
+-
+-### 2. Environment Setup
+-- Development environment using WSL
+-- NGINX running in WSL for development using NGINX Proxy Manager
+-- Docker environment being set up
+-- SSL certificates in place for development (self-signed)
+-- Staging and Production environment will use NGINX Server Configs and letsencrypt SSL certificates
+-
+-### 3. Service Status
+-
+-#### Keycloak (auth.mrx8086.com)
+-- NGINX configuration complete
+-- Docker setup complete
+-- Keycloak is running behind a reverse proxy
+-- Implemented setup_realm.js script for automated realm, client and user setup
+-- SSL certificates configured (self-signed)
+-- `setup_realm.js` configures the `office-automation` realm, `nextcloud`, `paperless`, and `nodered` clients.
+-- Test users `testadmin`, `testuser` and `testserviceuser` are also created.
+-- Client Scopes for `openid`, `profile` and `groups-nextcloud` are added to the nextcloud client.
+-- Groups `nextcloud-admins`, `nextcloud-users`, `nextcloud-youpi` and `nextcloud-service` are created.
+-
+-#### Nextcloud (cloud.mrx8086.com)
+-- NGINX configuration complete
+-- Docker setup complete
+-- SSL certificates configured
+-- Nextcloud is configured to use Keycloak for authentication
+-
+-#### Paperless (docs.mrx8086.com)
+-- NGINX configuration complete
+-- Docker setup pending
+-- SSL certificates configured
+-
+-#### Node-RED (automate.mrx8086.com)
+-- NGINX configuration complete
+-- Docker setup pending
+-- SSL certificates configured
+-- Chosen over n8n for better open-source compatibility
+-
+-### 4. Security
+-- Automated password generation implemented
+-- Encrypted credentials storage system in place
+-- SSL certificates managed and deployed
+-
+-### 5. Development Decisions
+-- Using WSL for development environment
+-- NGINX running directly in WSL for development
+-- Docker containers for all services
+-- Focusing on completely open-source solutions
+-- Development environment uses Nginx Proxy Manager
+-- Staging and Production will use Nginx Server Config files
+-
+-## Next Steps
+-1. Complete Paperless and Node-RED docker setup
+-2. Test Paperless and Node-RED authentication against Keycloak
+-3. Proceed with remaining service deployments
+-4. Setup Letsencrypt SSL Certificates in the Staging Environment
+-
+-## Important Files Location
+-- NGINX configs: /config/nginx/sites-available/
+-- SSL certificates: /config/nginx/ssl/mrx8086.com/
+-- Docker compose: /docker/docker-compose.yml
+-- Environment variables: /config/.env
+-- Encrypted credentials: /config/credentials/
+-- Keycloak setup script: /scripts/install/setup_realm.js
+-
+-## Development Environment
+-- Domain: mrx8086.com
+-- SSL certificates in place (self-signed)
+-- NGINX running in WSL
+-- Docker running in WSL
+-```
+-```markdown
+-# Ansible Setup Documentation
+-
+-## Overview
+-Ansible wird für das automatisierte Deployment des Automated Office Systems verwendet.
+-
+-## Roles Structure
+-
+-### Common Role
+-- Basis-Systemkonfiguration
+-- Sicherheitseinstellungen (fail2ban, UFW)
+-- Grundlegende Systempakete
+-
+-```yaml
+-# Standardvariablen
+-timezone: "Europe/Berlin"
+-fail2ban_bantime: 600
+-fail2ban_findtime: 600
+-fail2ban_maxretry: 3
+-```
+-
+-### Docker Role
+-- Docker Installation und Konfiguration
+-- Docker Compose Setup
+-- Docker Netzwerk-Konfiguration
+-
+-```yaml
+-# Docker Standardvariablen
+-docker_version: "latest"
+-docker_compose_version: "2.21.0"
+-docker_users: ["{{ ansible_user }}"]
+-```
+-
+-### NGINX Role
+-- NGINX Installation
+-- SSL/TLS Setup
+-- Virtual Host Konfiguration
+-
+-```yaml
+-# NGINX Standardvariablen
+-nginx_worker_processes: auto
+-nginx_worker_connections: 1024
+-nginx_client_max_body_size: "100M"
+-```
+-
+-### Services Role
+-- Deployment der Docker-Container
+-- Service-spezifische Konfigurationen
+-- Datenpersistenz-Setup
+-
+-## Inventory Structure
+-```plaintext
+-inventory/
+-├── production/
+-└── staging/
+-    └── hosts
+-```
+-
+-## Variables
+-```yaml
+-# vars/defaults/main.yml
+-base_domain: "example.com"
+-ssl_email: "admin@example.com"
+-
+-services:
+-  keycloak: true
+-  nextcloud: true
+-  paperless: true
+-  nodered: true
+-```
+-```yaml
+-# ansible/roles/common/defaults/main.yml
+----
+-# System
+-timezone: "Europe/Berlin"
+-
+-# Security
+-fail2ban_bantime: 600
+-fail2ban_findtime: 600
+-fail2ban_maxretry: 3
+-
+-# Firewall ports to open
+-ufw_allowed_ports:
+-  - { port: 22, proto: tcp }  # SSH
+-  - { port: 80, proto: tcp }  # HTTP
+-  - { port: 443, proto: tcp } # HTTPS
+-```
+-```yaml
+-# ansible/roles/docker/defaults/main.yml
+----
+-# Docker Standardvariablen
+-docker_version: "latest"
+-docker_compose_version: "2.21.0"
+-docker_users: ["{{ ansible_user }}"]
+-```
+-```yaml
+-# ansible/roles/nginx/defaults/main.yml
+----
+-# NGINX Standardvariablen
+-nginx_worker_processes: auto
+-nginx_worker_connections: 1024
+-nginx_client_max_body_size: "100M"
+-```
+-```yaml
+-# ansible/vars/defaults/main.yml
+----
+-# Domain-Konfiguration
+-base_domain: "example.com"
+-ssl_email: "admin@example.com"
+-
+-# Aktivierte Services
+-services:
+-  keycloak: true
+-  nextcloud: true
+-  paperless: true
+-  nodered: true
+-
+-# Ports
+-keycloak_port: 8080
+-nextcloud_port: 8081
+-paperless_port: 8000
+-nodered_port: 1880
+-
+-# Docker-Konfiguration
+-docker_compose_version: "2.21.0"
+-```
+-## Deployment Flow
+-1. Common Role: Systemvorbereitung
+-2. Docker Role: Container-Runtime
+-3. NGINX Role: Reverse Proxy
+-4. Services Role: Anwendungen
+-
+-## Wichtige Befehle
+-```bash
+-# Staging Deployment
+-ansible-playbook -i inventory/staging site.yml
+-
+-# Production Deployment
+-ansible-playbook -i inventory/production site.yml
+-```
+-
+-## Sicherheitsaspekte
+-- Automatische Passwortverwaltung
+-- SSL/TLS-Konfiguration
+-- Firewall-Einstellungen
+-- Fail2ban-Integration
+-
+-## Entwicklungshinweise
+-- Lokales Testing über WSL
+-- Staging-Umgebung für Tests
+-- Produktionsumgebung für finale Deployments
+-
+-## Updates und Wartung
+-- Regelmäßige Updates über Ansible
+-- Backup-Integration
+-- Monitoring-Setup
+-```
+-```bash
+-#!/bin/bash
+-set -e
+-
+-# Ensure we're in the project root directory
+-PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+-
+-# Define directories relative to project root
+-CREDENTIALS_DIR="${PROJECT_ROOT}/config/credentials"
+-DOCKER_DIR="${PROJECT_ROOT}/docker"
+-KEYCLOAK_SETUP_DIR="${PROJECT_ROOT}/scripts/setup/keycloak"
+-ANSIBLE_PLAYBOOK="${PROJECT_ROOT}/ansible/site.yml"
+-ANSIBLE_INVENTORY="${PROJECT_ROOT}/ansible/inventory/staging/hosts"
+-NEXTCLOUD_DATA_DIR="${PROJECT_ROOT}/data/nextcloud/data"
+-TEMP_FILE=$(mktemp)
+-KEYCLOAK_DB_DIR="${PROJECT_ROOT}/data/keycloak-db"
+-
+-# Create necessary directories
+-sudo mkdir -p "${CREDENTIALS_DIR}"
+-sudo mkdir -p "${DOCKER_DIR}"
+-sudo mkdir -p "${KEYCLOAK_SETUP_DIR}"
+-
+-# Initialize password variables
+-KEYCLOAK_ADMIN_PASSWORD=""
+-KC_DB_PASSWORD=""
+-TESTADMIN_PASSWORD=""
+-TESTUSER_PASSWORD=""
+-TESTSERVICEUSER_PASSWORD=""
+-KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=""
+-
+-# Function to read a password from a .env file
+-read_password_from_env() {
+-    local env_file="$1"
+-    local variable_name="$2"
+-    if [ -f "$env_file" ]; then
+-        grep "^${variable_name}=" "$env_file" | cut -d '=' -f2
+-    fi
+-}
+-
+-# Function to generate secure passwords
+-generate_password() {
+-    openssl rand -base64 32
+-}
+-
+-# Function to generate password if empty
+-generate_password_if_empty() {
+-    local variable_name="$1"
+-    eval "local value=\$$variable_name"
+-    if [ -z "$value" ]; then
+-        eval "$variable_name=\"$(generate_password)\""
+-        echo ">>> Generiertes Passwort für: $variable_name"
+-    fi
+-}
+-
+-# Function to create .env file
+-create_env_file() {
+-    local env_file="$1"
+-    local content="$2"
+-    if [ ! -f "$env_file" ]; then
+-        echo "$content" > "$env_file"
+-        echo ">>> .env file created: $env_file"
+-    else
+-        echo ">>> .env file already exists: $env_file"
+-    fi
+-}
+-
+-echo ">>> Überprüfe bestehende .env Dateien und lese Passwörter..."
+-
+-# Try reading passwords from existing .env files
+-if [ -f "$DOCKER_DIR/.env" ]; then
+-    KC_DB_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KC_DB_PASSWORD")
+-    KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$DOCKER_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD")
+-fi
+-
+-if [ -f "$KEYCLOAK_SETUP_DIR/.env" ]; then
+-    KEYCLOAK_ADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_ADMIN_PASSWORD") # Überschreibt ggf. den Wert aus docker/.env
+-    TESTADMIN_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTADMIN_PASSWORD")
+-    TESTUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTUSER_PASSWORD")
+-    TESTSERVICEUSER_PASSWORD=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "TESTSERVICEUSER_PASSWORD")
+-    KEYCLOAK_NEXTCLOUD_CLIENT_SECRET=$(read_password_from_env "$KEYCLOAK_SETUP_DIR/.env" "KEYCLOAK_NEXTCLOUD_CLIENT_SECRET")
+-fi
+-
+-echo ">>> Generiere neue Passwörter für fehlende Werte..."
+-
+-# Generate passwords if they are still empty
+-generate_password_if_empty KEYCLOAK_ADMIN_PASSWORD
+-generate_password_if_empty KC_DB_PASSWORD
+-generate_password_if_empty TESTADMIN_PASSWORD
+-generate_password_if_empty TESTUSER_PASSWORD
+-generate_password_if_empty TESTSERVICEUSER_PASSWORD
+-generate_password_if_empty KEYCLOAK_NEXTCLOUD_CLIENT_SECRET
+-
+-# Date for documentation
+-SETUP_DATE=$(date '+%Y-%m-%d_%H-%M-%S')
+-
+-# Create credentials content
+-CREDENTIALS_CONTENT=$(cat <<EOL
+-Setup Date: ${SETUP_DATE}
+-
+-Keycloak Admin Credentials:
+-Username: admin
+-Password: ${KEYCLOAK_ADMIN_PASSWORD}
+-
+-Keycloak Database Credentials:
+-Username: keycloak
+-Password: ${KC_DB_PASSWORD}
+-
+-Test User Credentials:
+-Admin Password: ${TESTADMIN_PASSWORD}
+-User Password: ${TESTUSER_PASSWORD}
+-Service User Password: ${TESTSERVICEUSER_PASSWORD}
+-Nextcloud Client Secret: ${KEYCLOAK_NEXTCLOUD_CLIENT_SECRET}
+-
+-EOL
+-)
+-
+-# Store credentials hash
+-CREDENTIALS_HASH=$(echo "$CREDENTIALS_CONTENT" | sha256sum | awk '{print $1}')
+-echo "$CREDENTIALS_HASH" > "${CREDENTIALS_DIR}/credentials_hash.txt"
+-echo ">>> Credentials hash stored in: ${CREDENTIALS_DIR}/credentials_hash.txt"
+-
+-# Set GPG PASSPHRASE
+-export GPG_PASSPHRASE=$(generate_password)
+-# Set GPG agent environment variable
+-export GPG_TTY=$(tty)
+-
+-echo ">>> Trying openssl encryption first"
+-# Alternative Verschlüsselung mit Openssl
+-echo "$CREDENTIALS_CONTENT" > "$TEMP_FILE"
+-          if openssl enc -aes-256-cbc -pbkdf2 -salt -in "$TEMP_FILE" -out "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" -k "$GPG_PASSPHRASE" ; then
+-             echo ">>> Credentials encrypted successfully using openssl"
+-             mv  "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.enc" "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg"
+-        else
+-           echo ">>> Openssl encryption failed, trying gpg"
+-
+-          # Attempt to kill existing gpg agent
+-          gpgconf --kill gpg-agent 2>/dev/null
+-          echo ">>> Attempting to manually start gpg-agent with pinentry-curses"
+-          gpg-agent --daemon --pinentry-program /usr/bin/pinentry-curses
+-          gpg-connect-agent /bye 2>/dev/null
+-          eval $(gpg-agent --daemon)
+-          gpg-connect-agent updatestartuptty /bye 2>/dev/null
+-
+-          # Attempt to encrypt credentials using GPG with error handling
+-          if echo "$CREDENTIALS_CONTENT" | gpg --symmetric --cipher-algo AES256 -vvv -o "${CREDENTIALS_DIR}/credentials_${SETUP_DATE}.txt.gpg" ; then
+-                echo ">>> Credentials encrypted successfully using gpg."
+-          else
+-             echo
+-
+-
+-
+-
+-
+-
+-             ```
+\ No newline at end of file

+ 6 - 0
scripts/setup/paperless/.env

@@ -0,0 +1,6 @@
+KEYCLOAK_URL=https://auth.mrx8086.com
+KEYCLOAK_ADMIN_USER=admin
+KEYCLOAK_ADMIN_PASSWORD=9aD5Fddh457QqmvQqr6Rb8bu
+PAPERLESS_CLIENT_ID=paperless
+KEYCLOAK_PAPERLESS_CLIENT_SECRET=CSbw9ldbZBUGGQSJoAUEg10QKgjdb6Tq
+PAPERLESS_URL=https://docs.mrx8086.com

+ 114 - 0
scripts/setup/paperless/package-lock.json

@@ -0,0 +1,114 @@
+{
+    "name": "paperless",
+    "lockfileVersion": 3,
+    "requires": true,
+    "packages": {
+        "": {
+            "dependencies": {
+                "axios": "^1.6.7",
+                "dotenv": "^16.4.5"
+            }
+        },
+        "node_modules/asynckit": {
+            "version": "0.4.0",
+            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+        },
+        "node_modules/axios": {
+            "version": "1.7.9",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
+            "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
+            "dependencies": {
+                "follow-redirects": "^1.15.6",
+                "form-data": "^4.0.0",
+                "proxy-from-env": "^1.1.0"
+            }
+        },
+        "node_modules/combined-stream": {
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+            "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+            "dependencies": {
+                "delayed-stream": "~1.0.0"
+            },
+            "engines": {
+                "node": ">= 0.8"
+            }
+        },
+        "node_modules/delayed-stream": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+            "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+            "engines": {
+                "node": ">=0.4.0"
+            }
+        },
+        "node_modules/dotenv": {
+            "version": "16.4.7",
+            "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+            "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://dotenvx.com"
+            }
+        },
+        "node_modules/follow-redirects": {
+            "version": "1.15.9",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+            "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+            "funding": [
+                {
+                    "type": "individual",
+                    "url": "https://github.com/sponsors/RubenVerborgh"
+                }
+            ],
+            "engines": {
+                "node": ">=4.0"
+            },
+            "peerDependenciesMeta": {
+                "debug": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/form-data": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
+            "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
+            "dependencies": {
+                "asynckit": "^0.4.0",
+                "combined-stream": "^1.0.8",
+                "mime-types": "^2.1.12"
+            },
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "node_modules/mime-db": {
+            "version": "1.52.0",
+            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/mime-types": {
+            "version": "2.1.35",
+            "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+            "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+            "dependencies": {
+                "mime-db": "1.52.0"
+            },
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
+        "node_modules/proxy-from-env": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+        }
+    }
+}

+ 7 - 0
scripts/setup/paperless/package.json

@@ -0,0 +1,7 @@
+{
+    "type": "module",
+    "dependencies": {
+      "axios": "^1.6.7",
+      "dotenv": "^16.4.5"
+    }
+  }

+ 521 - 0
scripts/setup/paperless/setup_realm.js

@@ -0,0 +1,521 @@
+import dotenv from 'dotenv';
+import axios from 'axios';
+
+// Load environment variables
+dotenv.config();
+console.log('Environment variables loaded.');
+
+// Configuration constants
+const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'https://auth.mrx8086.com';
+const ADMIN_USERNAME = process.env.KEYCLOAK_ADMIN_USER;
+const ADMIN_PASSWORD = process.env.KEYCLOAK_ADMIN_PASSWORD;
+const REALM_NAME = 'office-automation';
+
+console.log('Configuration constants set:', { KEYCLOAK_URL, ADMIN_USERNAME, REALM_NAME });
+
+// Client ID for Paperless
+const PAPERLESS_CLIENT_ID = process.env.PAPERLESS_CLIENT_ID || 'paperless';
+
+// Helper function for API error handling
+const handleAxiosError = (error, operation, config, response) => {
+    console.error(`Error during ${operation}:`);
+    if (config) {
+        console.error('Request:', {
+            method: config.method,
+            url: config.url,
+            headers: config.headers,
+            data: config.data,
+        });
+    }
+    if (error.response) {
+        console.error('Response:', {
+            status: error.response.status,
+            data: error.response.data
+        });
+    } else {
+        console.error('Error Message:', error.message);
+    }
+    throw error;
+};
+
+// Get Admin Token
+async function getAdminToken() {
+    console.log('Getting admin token...');
+    try {
+        const response = await axios.post(
+            `${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token`,
+            new URLSearchParams({
+                'client_id': 'admin-cli',
+                'username': ADMIN_USERNAME,
+                'password': ADMIN_PASSWORD,
+                'grant_type': 'password'
+            }),
+            {
+                headers: {
+                    'Content-Type': 'application/x-www-form-urlencoded'
+                }
+            }
+        );
+        console.log('Admin token received.');
+        return response.data.access_token;
+    } catch (error) {
+        handleAxiosError(error, 'getting admin token');
+    }
+}
+
+
+// Function to get client information by clientId
+async function getClientByClientId(token, clientId) {
+    console.log(`Getting client information for ${clientId}...`);
+    try {
+        const response = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`, {
+            headers: { 'Authorization': `Bearer ${token}` },
+            params: { clientId }
+        });
+        if (response.data.length === 0) {
+            console.log(`Client ${clientId} not found`);
+            return null;
+        }
+        console.log(`Client ${clientId} found.`);
+        return response.data[0];
+    } catch (error) {
+        handleAxiosError(error, `getting client ${clientId}`);
+        return null;
+    }
+}
+
+// Check if client exists
+const checkClientExists = async (token, clientId) => !!await getClientByClientId(token, clientId);
+
+// Get client mappers by client ID
+async function getClientMappers(token, clientId) {
+    console.log(`Getting client mappers for ${clientId}...`);
+    const client = await getClientByClientId(token, clientId);
+    if (!client) {
+        console.log(`Client ${clientId} not found, no mappers to get.`);
+        return [];
+    }
+    try {
+        const response = await axios.get(
+            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
+            { headers: { 'Authorization': `Bearer ${token}` } }
+        );
+        console.log(`Client mappers for ${clientId} retrieved.`);
+        return response.data;
+    } catch (error) {
+        handleAxiosError(error, `getting client mappers for ${clientId}`, error.config, error.response);
+        return [];
+    }
+}
+
+// Get client scopes for a client
+async function getClientScopes(token, clientId) {
+    console.log(`Getting client scopes for ${clientId}...`);
+    const client = await getClientByClientId(token, clientId);
+    if (!client) {
+        console.log(`Client ${clientId} not found, no client scopes to get.`);
+        return [];
+    }
+    try {
+        const response = await axios.get(
+            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/client-scopes`,
+            { headers: { 'Authorization': `Bearer ${token}` } }
+        );
+        console.log(`Client scopes for ${clientId} retrieved.`);
+        return response.data;
+    } catch (error) {
+        handleAxiosError(error, `getting client scopes for ${clientId}`, error.config, error.response);
+        return [];
+    }
+}
+
+// Get a specific client scope by name
+async function getClientScope(token, scopeName) {
+    console.log(`Getting client scope "${scopeName}"...`);
+    try {
+        const response = await axios.get(
+            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes`,
+            { headers: { 'Authorization': `Bearer ${token}` } }
+        );
+        const foundScope = response.data.find(scope => scope.name === scopeName);
+        if (!foundScope) {
+            console.log(`Client Scope "${scopeName}" not found`);
+            return null;
+        }
+        console.log(`Client scope "${scopeName}" found:`, foundScope);
+        return foundScope;
+    } catch (error) {
+        handleAxiosError(error, `getting client scope ${scopeName}`, error.config, error.response);
+        return null;
+    }
+}
+
+// Add a default client scope to a client
+async function addDefaultClientScope(token, clientId, scopeName) {
+    console.log(`Adding client scope "${scopeName}" as default for client "${clientId}"...`);
+    const client = await getClientByClientId(token, clientId);
+    const scope = await getClientScope(token, scopeName);
+    if (!client || !scope) {
+        console.log(`Client "${clientId}" or scope "${scopeName}" not found, cannot add as default scope.`);
+        return;
+    }
+    try {
+        await axios.put(
+            `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/default-client-scopes/${scope.id}`,
+            null,
+            {
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                }
+            }
+        );
+        console.log(`Client scope "${scopeName}" added as default scope for client "${clientId}"`);
+    } catch (error) {
+        handleAxiosError(error, `adding client scope "${scopeName}" as default for client "${clientId}"`);
+    }
+}
+
+// Create client and manage mappers
+async function createClient(token, clientId, clientName, redirectUris) {
+    console.log(`Creating client "${clientId}"...`);
+    let client = await getClientByClientId(token, clientId);
+
+    if (!client) {
+        const clientConfig = {
+            clientId: clientId,
+            name: clientName,
+            enabled: true,
+            protocol: "openid-connect",
+            publicClient: false,
+            authorizationServicesEnabled: false,
+            serviceAccountsEnabled: false,
+            standardFlowEnabled: true,
+            implicitFlowEnabled: false,
+            directAccessGrantsEnabled: true,
+            redirectUris: redirectUris,
+            webOrigins: ["+"],
+            defaultClientScopes: ["roles"],
+            optionalClientScopes: ["address", "phone", "offline_access", "microprofile-jwt"],
+            rootUrl: process.env.PAPERLESS_URL,
+             baseUrl: process.env.PAPERLESS_URL,
+            adminUrl: process.env.PAPERLESS_URL,
+        };
+        try {
+            const response = await axios.post(
+                `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients`,
+                clientConfig,
+                {
+                    headers: {
+                        'Authorization': `Bearer ${token}`,
+                        'Content-Type': 'application/json'
+                    }
+                }
+            );
+            console.log(`Client "${clientId}" created successfully`);
+            client = response.data;
+        } catch (error) {
+            handleAxiosError(error, `creating client: ${clientId}`);
+            return;
+        }
+    } else {
+         console.log(`Client "${clientId}" already exists, checking mappers and client secret`);
+    }
+
+     if (client) {
+        try {
+            await axios.put(
+                `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}`,
+                { ...client, secret: process.env[`KEYCLOAK_${clientId.replace(/[^a-zA-Z0-9]/g, '').toUpperCase()}_CLIENT_SECRET`] },
+                {
+                    headers: {
+                        'Authorization': `Bearer ${token}`,
+                        'Content-Type': 'application/json'
+                    }
+                }
+            );
+            console.log(`Set client secret for client: ${clientId}`);
+        } catch (error) {
+            handleAxiosError(error, `setting client secret for client: ${clientId}`, error.config, error.response);
+        }
+
+        const existingMappers = await getClientMappers(token, clientId);
+        const requiredMappers = [
+            {
+                name: "groups",
+                protocol: "openid-connect",
+                protocolMapper: "oidc-group-membership-mapper",
+                config: {
+                    "full.path": "true",
+                    "id.token.claim": "true",
+                    "access.token.claim": "true",
+                    "userinfo.token.claim": "true",
+                    "claim.name": "groups"
+                }
+            },
+            {
+                name: "realm roles",
+                protocol: "openid-connect",
+                protocolMapper: "oidc-usermodel-realm-role-mapper",
+                config: {
+                    "id.token.claim": "true",
+                    "access.token.claim": "true",
+                    "userinfo.token.claim": "true",
+                    "claim.name": "roles",
+                    "jsonType.label": "String",
+                    "multivalued": "true"
+                }
+            }
+        ];
+
+        for (const mapper of requiredMappers) {
+             const existingMapper = existingMappers.find(m => m.name === mapper.name);
+            try {
+                if (existingMapper) {
+                    await axios.put(
+                        `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models/${existingMapper.id}`,
+                        { ...existingMapper, ...mapper },
+                        {
+                            headers: {
+                                'Authorization': `Bearer ${token}`,
+                                'Content-Type': 'application/json'
+                            }
+                        }
+                    );
+                    console.log(`Mapper "${mapper.name}" updated for client "${clientId}"`);
+                } else {
+                    await axios.post(
+                        `${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients/${client.id}/protocol-mappers/models`,
+                        mapper,
+                        {
+                            headers: {
+                                'Authorization': `Bearer ${token}`,
+                                'Content-Type': 'application/json'
+                            }
+                        }
+                    );
+                    console.log(`Mapper "${mapper.name}" created for client "${clientId}"`);
+                }
+            } catch (error) {
+                handleAxiosError(error, `managing mapper "${mapper.name}" for client "${clientId}"`, error.config, error.response);
+            }
+        }
+
+        await addDefaultClientScope(token, clientId, "openid");
+        await addDefaultClientScope(token, clientId, "profile");
+        await addDefaultClientScope(token, clientId, "groups-paperless");
+    }
+}
+// Create default groups
+async function createDefaultGroups(token) {
+    console.log('Creating default groups...');
+    const groups = [
+        { name: "paperless-admins", path: "/paperless-admins", attributes: { "description": ["Paperless administrators"] } },
+        { name: "paperless-users", path: "/paperless-users", attributes: { "description": ["Paperless regular users"] } },
+        { name: "paperless-service", path: "/paperless-service", attributes: { "description": ["Paperless service user"] } }
+    ];
+
+    for (const group of groups) {
+        try {
+             const existingGroups = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`, {
+                headers: { 'Authorization': `Bearer ${token}` },
+                params: { search: group.name, exact: true } // Added exact: true for precise matching
+            });
+
+            if (existingGroups.data.length > 0) {
+                console.log(`Group "${group.name}" already exists`);
+                continue;
+            }
+
+            await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`, group, {
+                headers: {
+                    'Authorization': `Bearer ${token}`,
+                    'Content-Type': 'application/json'
+                }
+            });
+            console.log(`Group "${group.name}" created successfully`);
+        } catch (error) {
+             if (error.response?.status === 409) {
+                console.log(`Group "${group.name}" already exists`);
+            } else {
+                handleAxiosError(error, `creating group: ${group.name}`);
+            }
+        }
+    }
+}
+
+// Function to add users to groups
+async function addUsersToGroups(token) {
+    console.log('Adding users to groups...');
+    const users = [
+        { username: "testadmin", groups: ["paperless-admins", "paperless-users"] },
+        { username: "testuser", groups: ["paperless-users"] },
+        { username: "testserviceuser", groups: ["paperless-service"] }
+    ];
+
+    for (const user of users) {
+        try {
+             const existingUsers = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users`, {
+                headers: { 'Authorization': `Bearer ${token}` },
+                params: { username: user.username, exact: true } // Added exact: true for precise matching
+            });
+
+             if (existingUsers.data.length === 0) {
+                console.log(`User "${user.username}" not found`);
+                continue;
+            }
+
+            const userId = existingUsers.data[0].id;
+
+             for (const groupName of user.groups) {
+                 const groupsResponse = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups`, {
+                     headers: { 'Authorization': `Bearer ${token}` },
+                     params: { search: groupName, exact: true }
+                 });
+                 if (groupsResponse.data.length > 0) {
+                    const groupId = groupsResponse.data[0].id;
+                    try {
+                         await axios.put(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users/${userId}/groups/${groupId}`, {}, {
+                            headers: {
+                                'Authorization': `Bearer ${token}`,
+                                'Content-Type': 'application/json'
+                            }
+                        });
+                        console.log(`User "${user.username}" added to group "${groupName}"`);
+                    } catch (error) {
+                        handleAxiosError(error, `adding user "${user.username}" to group "${groupName}"`, error.config, error.response);
+                    }
+                } else {
+                  console.log(`Group "${groupName}" not found`);
+                 }
+             }
+        } catch (error) {
+            handleAxiosError(error, `adding user "${user.username}" to groups`, error.config, error.response);
+        }
+    }
+}
+
+async function createGroupsPaperlessScope(token) {
+    const scopeName = "groups-paperless";
+    const mapperName = "groups-mapper";
+    console.log(`Starting createGroupsPaperlessScope`);
+    let clientScope = await getClientScope(token, scopeName);
+
+    if (!clientScope) {
+        try {
+            console.log(`Creating client scope "${scopeName}"`);
+            clientScope = await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes`,
+                {
+                    "name": scopeName,
+                    "protocol": "openid-connect",
+                    "description": "Provides access to user group information for Paperless.", // Hinzugefügt: Beschreibung
+                    "attributes": {},
+                    "consentScreenText": "Grant access to user groups in Paperless",
+                    "includeInTokenScope": true
+                },
+                {
+                    headers: {
+                        'Authorization': `Bearer ${token}`,
+                        'Content-Type': 'application/json'
+                    }
+                });
+            console.log(`Client scope "${scopeName}" created successfully`);
+            clientScope = response.data;
+        } catch (error) {
+            console.error(`Error creating client scope "${scopeName}":`, error);
+            handleAxiosError(error, `creating ${scopeName} client scope`, error.config, error.response);
+            return;
+        }
+    } else {
+        console.log(`Client scope "${scopeName}" exists, skipping creation`);
+    }
+
+    console.log("Client scope creation step finished");
+    if (clientScope) {
+        console.log(`Check for mapper "${mapperName}" in scope "${scopeName}"`);
+        try {
+            const mappersResponse = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes/${clientScope.id}/protocol-mappers/models`,
+                { headers: { 'Authorization': `Bearer ${token}` } }
+            );
+            if (!mappersResponse.data.find(m => m.name === mapperName)) {
+                try {
+                    await axios.post(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/client-scopes/${clientScope.id}/protocol-mappers/models`,
+                        {
+                            "name": mapperName,
+                            "protocol": "openid-connect",
+                            "protocolMapper": "oidc-group-membership-mapper",
+                            "config": {
+                                "full.path": "false",
+                                "id.token.claim": "false",
+                                "access.token.claim": "true",
+                                "userinfo.token.claim": "true",
+                                "claim.name": "groups",
+                                "add.to.introspection": "false"
+                            }
+                        },
+                        {
+                            headers: {
+                                'Authorization': `Bearer ${token}`,
+                                'Content-Type': 'application/json'
+                            }
+                        });
+                    console.log(`Mapper "${mapperName}" created for client scope "${scopeName}"`);
+                } catch (error) {
+                    console.error(`Error creating mapper "${mapperName}" for scope "${scopeName}":`, error);
+                    handleAxiosError(error, `creating mapper for ${scopeName}`, error.config, error.response);
+                }
+            } else {
+                console.log(`Mapper "${mapperName}" exists in client scope "${scopeName}", skipping creation`);
+            }
+        } catch (error) {
+            console.error("Error checking for mappers:", error);
+            handleAxiosError(error, `checking mappers for ${scopeName}`, error.config, error.response);
+        }
+    }
+    console.log("Finished createGroupsPaperlessScope");
+}
+
+// Main function
+async function setupPaperlessRealm() {
+    try {
+        console.log('Starting Paperless Keycloak setup...');
+        const token = await getAdminToken();
+
+        // Create Paperless client
+        await createClient(token, PAPERLESS_CLIENT_ID, PAPERLESS_CLIENT_ID, [`https://docs.mrx8086.com/*`]);
+
+        // Create groups
+        await createDefaultGroups(token);
+
+         // Create client scope groups-paperless
+        await createGroupsPaperlessScope(token);
+
+        // Add users to groups
+        await addUsersToGroups(token);
+
+
+         // Read the configuration of the Office-Automation realm with Admin Token
+        if (token) {
+            console.log("Master Realm Admin Token:", token);
+            try {
+                const realmConfig = await axios.get(`${KEYCLOAK_URL}/admin/realms/${REALM_NAME}`, {
+                    headers: { 'Authorization': `Bearer ${token}` }
+                });
+                console.log("Office Automation Realm Configuration:", realmConfig.data);
+            } catch (error) {
+                handleAxiosError(error, 'getting office realm configuration', error.config, error.response);
+            }
+        } else {
+            console.error("Error getting Master Realm admin token");
+        }
+
+        console.log('Paperless Keycloak setup completed successfully');
+
+    } catch (error) {
+        console.error('Paperless Keycloak setup failed:', error);
+        process.exit(1);
+    }
+}
+
+// Execute the script
+setupPaperlessRealm();