Zum Inhalt

Konfiguration

mandari wird über Umgebungsvariablen konfiguriert, in der Docker-Installation über die Datei .env. Diese Seite ist die Referenz. Werte in der Spalte Standard gelten, wenn die Variable nicht gesetzt ist.

Nicht jede Variable erreicht die Dienste

Unter Docker Compose erreicht einen Dienst nur, was docker-compose.yml in seinem Abschnitt environment nennt. Die Anwendung und ihre Worker erhalten die Variablen aus x-app-environment, der Ingestor die aus seinem eigenen Abschnitt. Fehlt eine Variable dort, wirkt ein Eintrag nur in der .env nicht: Tragen Sie sie im Abschnitt environment des Dienstes oder in einer zusätzlichen Compose-Datei ein. Im Helm-Chart gehören solche Variablen in app.extraEnv (Anwendung und Worker) bzw. ingestor.extraEnv.

Pflichtwerte

Variable Bedeutung
DOMAIN Domain der Installation, zum Beispiel mandari.example.org. Bei localhost bleibt HTTPS aus.
ACME_EMAIL E-Mail-Adresse für Zertifikatshinweise von Let's Encrypt
SECRET_KEY Django-Geheimschlüssel, lang und zufällig
ENCRYPTION_MASTER_KEY Base64-kodierter 256-Bit-Schlüssel (openssl rand -base64 32). Verschlüsselt die mandantenspezifischen Schlüssel. Nie einfach austauschen, sonst sind verschlüsselte Daten unlesbar; für einen Wechsel siehe ENCRYPTION_MASTER_KEY_PREVIOUS.
DATABASE_URL Verbindung zur Datenbank, zum Beispiel postgresql://user:pass@postgres:5432/mandari. Im Compose-Stack aus POSTGRES_USER, POSTGRES_PASSWORD und POSTGRES_DB zusammengesetzt.
ALLOWED_HOSTS Kommagetrennte Hostnamen, unter denen die Anwendung erreichbar ist
SITE_URL Öffentliche Basis-URL, zum Beispiel https://mandari.example.org. Basis für Links in E-Mails und OParl-IDs.
POSTGRES_PASSWORD, REDIS_PASSWORD Passwörter für Datenbank und Redis; ohne sie startet docker-compose.yml nicht

Unter Docker Compose setzt docker-compose.yml ALLOWED_HOSTS, SITE_URL und CSRF_TRUSTED_ORIGINS selbst aus DOMAIN und DATABASE_URL aus den POSTGRES_*-Werten, außerdem DEBUG=false. Eigene Werte dieser Variablen in der .env wirken dort nicht.

Eigene Variablen unter Docker Compose

Unter Docker Compose erhält ein Dienst nur die Variablen, die docker-compose.yml ihm nennt; die .env dient dort nur zum Einsetzen von Werten in die Compose-Datei. Viele Variablen dieser Seite reicht docker-compose.yml nicht durch, das steht bei jeder Gruppe.

Ändern Sie dafür nicht die versionierte docker-compose.yml. update.sh holt bei jedem Update den neuen Stand aus Git; mit einer geänderten Datei kann das scheitern, und die Installation läuft dann mit der alten Compose-Datei weiter. Legen Sie stattdessen eine docker-compose.override.yml daneben; das Repository ignoriert sie, und Docker Compose liest sie ohne weitere Angabe mit. Anwendung und Worker teilen sich in docker-compose.yml einen gemeinsamen Block (x-app-environment), auf den der Dienst mandari und die Worker nur verweisen. In der Override-Datei steht eine Variable deshalb bei jedem Dienst, der sie braucht, also für Anwendung und Worker bei mandari, worker, worker-heavy und worker-live:

# docker-compose.override.yml
x-eigene-umgebung: &eigene-umgebung
  EMAIL_HOST: smtp.example.org
  EMAIL_HOST_USER: mandari@example.org
  EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD}   # Wert aus der .env

services:
  mandari:
    environment: *eigene-umgebung
  worker:
    environment: *eigene-umgebung
  worker-heavy:
    environment: *eigene-umgebung
  worker-live:
    environment: *eigene-umgebung

Compose ergänzt die Umgebung dieser Dienste um die Einträge; danach docker compose up -d. Ist COMPOSE_FILE gesetzt (Betrieb auf mehreren Servern), liest Compose die Override-Datei nicht von selbst; dann gehört sie mit in diese Liste. Im Helm-Chart gehören solche Variablen in app.extraEnv (Anwendung und Worker) bzw. ingestor.extraEnv.

Allgemein

Variable Standard Bedeutung
DEBUG True (docker-compose.yml: false) Nur für die lokale Entwicklung einschalten; ohne Compose in Produktion ausdrücklich false setzen
TZ Europe/Berlin Zeitzone der Container
IMAGE_TAG latest Version der Container-Images, siehe Updates
PROVISIONING_API_KEY leer Aktiviert die Provisioning-API. Leer bedeutet abgeschaltet.
COMPOSE_PROJECT_NAME mandari Projektname für Container und Volumes; eine zweite Installation auf demselben Server braucht einen anderen
ENCRYPTION_MASTER_KEY_PREVIOUS leer Nur während eines Schlüsselwechsels: der bisherige Hauptschlüssel, mehrere durch Komma getrennt. Wird nur zum Lesen verwendet und danach wieder geleert; Ablauf in docs/KRYPTOKONZEPT.md im Repository.
CSRF_TRUSTED_ORIGINS SITE_URL Weitere vertrauenswürdige Ursprünge für Formulare und WebSockets, kommagetrennt mit Schema. Nur nötig, wenn ein anderer Host Formulare an diese Installation sendet.
MAIN_DOMAIN Host aus SITE_URL ohne www. Hauptdomain, etwa für Subdomains von Organisationen und als Standard von WEBAUTHN_RP_ID
SUBDOMAIN_REDIRECT_ENABLED true Subdomain einer Organisation leitet in ihren Arbeitsbereich weiter (fraktion.example.org nach /work/fraktion/)
PORTAL_HOSTS leer Bürgerportal einer Körperschaft unter eigenem Host: host=slug, kommagetrennt. Jeder Host muss zusätzlich in ALLOWED_HOSTS stehen; DNS, Zertifikat und Proxy richtet der Betrieb ein.
MARKETING_URL leer (mit DEBUG: http://localhost:8001) Adresse der Website, wenn sie nicht unter derselben Domain läuft
DEMO_INSTANCE false Macht die Installation zur öffentlichen Demo: kein Mailversand, keine KI, Passwort, zweiter Faktor und Konto nicht änderbar. Nie in einer Installation mit echten Daten setzen, siehe Demo-Umgebung.
DEMO_PASSWORD leer Nur mit DEMO_INSTANCE: festes Passwort aller Demo-Konten

Unter Docker Compose wirken aus dieser Tabelle TZ und ENCRYPTION_MASTER_KEY_PREVIOUS, die docker-compose.yml an die Dienste weiterreicht, sowie IMAGE_TAG und COMPOSE_PROJECT_NAME, die die Compose-Datei selbst liest; DEBUG steht dort fest auf false. Die übrigen tragen Sie unter Docker Compose in einer docker-compose.override.yml (siehe Eigene Variablen unter Docker Compose) ein, im Helm-Chart in app.extraEnv; ein Eintrag nur in der .env wirkt nicht.

Anmeldung und Zugriffsschutz

Variable Standard Bedeutung
TWO_FACTOR_ENFORCEMENT true (mit DEBUG: false) Pflicht zum zweiten Faktor für Administratoren und, je nach Einstellung, je Organisation bzw. Mandant
TWO_FACTOR_EXEMPT_EMAIL_DOMAINS demo.mandari.de E-Mail-Domains ohne diese Pflicht, nur für gemeinsam genutzte Demo-Zugänge ohne echte Daten
TWO_FACTOR_REQUIRE_SECURITY_KEY_FOR_SUPERUSERS false Plattform-Administration nur mit Sicherheitsschlüssel; erst einschalten, wenn die Schlüssel ausgegeben sind
WEBAUTHN_RP_ID MAIN_DOMAIN Relying-Party-ID für Sicherheitsschlüssel und Passkeys, gilt auch für Subdomains
WEBAUTHN_RP_NAME mandari Name, den Browser und Schlüssel anzeigen
ADMIN_ALLOWED_NETWORKS leer Django-Admin nur aus diesen Netzen (CIDR, kommagetrennt), leer = keine Beschränkung. Voraussetzung: Der vorgelagerte Proxy ersetzt X-Forwarded-For durch die echte Adresse.
SECURE_HSTS_SECONDS 31536000 Dauer des HSTS-Headers in Sekunden (nur ohne DEBUG)
SECURE_SSL_REDIRECT false Umleitung auf HTTPS durch Django; im Standard übernimmt das der Proxy

Keine dieser Variablen reicht docker-compose.yml durch. Im Standard gilt also die Pflicht zum zweiten Faktor; abweichende Werte gehören unter Docker Compose in einer docker-compose.override.yml (siehe Eigene Variablen unter Docker Compose), im Helm-Chart in app.extraEnv. Für die Bedienung siehe Konto und Sicherheit.

E-Mail

Den SMTP-Zugang pflegen Sie am einfachsten im Admin in den Systemeinstellungen; die Variablen EMAIL_* gelten nur, wenn dort nichts hinterlegt ist. Organisationen in Work können zusätzlich einen eigenen SMTP-Zugang hinterlegen.

Variable Standard Bedeutung
EMAIL_HOST, EMAIL_PORT leer, 587 SMTP-Server und Port
EMAIL_HOST_USER, EMAIL_HOST_PASSWORD leer Zugangsdaten
EMAIL_USE_TLS, EMAIL_USE_SSL true, false STARTTLS bzw. TLS von Anfang an
EMAIL_TIMEOUT 30 Zeitgrenze der SMTP-Verbindung in Sekunden
DEFAULT_FROM_EMAIL noreply@mandari.de Absender, wenn die Systemeinstellungen keinen nennen
EMAIL_MESSAGE_ID_DOMAIN Domain von DEFAULT_FROM_EMAIL, sonst Host aus SITE_URL Domain hinter dem @ der Message-ID und Name im EHLO. Setzen, wenn der Absender in den Systemeinstellungen eine andere Domain hat.
MAIL_QUEUE leer Mailarten, die nicht in der Anfrage, sondern als Auftrag im Worker (Warteschlange mail, mit Wiederholung) hinausgehen: kommagetrennte Muster wie work.*,konto.* oder *. Braucht TASKS_BACKEND=journal; leer = sofort.
MAIL_QUEUE_MAX_BYTES 20971520 Größere Mails (Text und Anhänge in Bytes) gehen sofort hinaus
INSIGHT_DIGEST_FROM_EMAIL DEFAULT_FROM_EMAIL Absender für Bürgerportal-Mails (Beschluss-Abos, Digest)
INSIGHT_ALERT_EMAILS leer Kommagetrennte Empfänger für Betriebsalarme. Ersatzweise INSIGHT_MODERATION_EMAILS, sonst alle Superuser.
INSIGHT_MODERATION_EMAILS leer Kommagetrennte Empfänger für Moderationshinweise der Ratsfragen

docker-compose.yml reicht von diesen nur DEFAULT_FROM_EMAIL, EMAIL_MESSAGE_ID_DOMAIN, MAIL_QUEUE, MAIL_QUEUE_MAX_BYTES und INSIGHT_ALERT_EMAILS durch. Für den SMTP-Zugang unter Docker Compose deshalb die Systemeinstellungen nutzen oder die EMAIL_*-Variablen in einer docker-compose.override.yml (siehe Eigene Variablen unter Docker Compose) eintragen.

Datenbank, Cache, Suche

Variable Standard Bedeutung
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB Zugangsdaten des Datenbank-Containers
REDIS_PASSWORD Passwort des Redis-Containers
REDIS_MAXMEMORY 256mb Speicherobergrenze von Redis
REDIS_URL redis://localhost:6379/0 Adresse von Redis; docker-compose.yml setzt sie selbst mit REDIS_PASSWORD
ELASTICSEARCH_URL http://localhost:9200 (docker-compose.yml: http://elasticsearch:9200) Adresse der Suche
ELASTICSEARCH_AUTO_INDEX True Änderungen sofort indexieren
DB_POOL true Verbindungspool der Anwendung an PostgreSQL
DB_POOL_MIN, DB_POOL_MAX 2, 10 vorgehaltene bzw. höchstens gleichzeitig genutzte Verbindungen je Prozess
DB_POOL_MAX_WAITING 20 So viele Anfragen dürfen auf eine Verbindung warten; jede weitere bekommt sofort 503. 0 = unbegrenzt.
DB_POOL_TIMEOUT 5 Sekunden Wartezeit bei erschöpftem Pool, danach 503
DB_POOL_MAX_LIFETIME 1800 Verbindungen nach so vielen Sekunden erneuern
DB_CONN_MAX_AGE 60 Lebensdauer einer Verbindung ohne Pool; mit Pool setzt die Anwendung 0

PostgreSQL im Compose-Stack. Diese Werte liest docker-compose.yml selbst aus der .env. Die Einstellungen von PostgreSQL wirken erst, wenn der Datenbankdienst neu startet (docker compose up -d postgres):

Variable Standard Bedeutung
POSTGRES_MEM_LIMIT 1g Speichergrenze des Containers; shared_buffers ist auf ein Viertel davon ausgelegt
POSTGRES_SHARED_BUFFERS, POSTGRES_EFFECTIVE_CACHE_SIZE 256MB, 768MB Puffer und angenommener Cache des Betriebssystems
POSTGRES_WORK_MEM, POSTGRES_MAINTENANCE_WORK_MEM 8MB, 128MB Speicher je Sortierung bzw. für Wartung
POSTGRES_RANDOM_PAGE_COST, POSTGRES_EFFECTIVE_IO_CONCURRENCY 1.1, 200 Annahmen für SSD-Speicher
POSTGRES_MAX_CONNECTIONS 100 Höchstzahl der Verbindungen aller Dienste zusammen
POSTGRES_MAX_WAL_SIZE 2GB Größe des Write-Ahead-Logs bis zum Checkpoint
POSTGRES_TEMP_FILE_LIMIT 5GB Obergrenze für temporäre Dateien je Sitzung
POSTGRES_SHARED_PRELOAD_LIBRARIES pg_stat_statements vorab geladene Erweiterungen; leer setzen schaltet die Abfragestatistik ab
WEBSITE_DB, WEBSITE_SECRET_KEY mandari_website, SECRET_KEY Datenbank und Schlüssel der Website

Die DB_POOL*- und DB_CONN_MAX_AGE-Werte und ELASTICSEARCH_AUTO_INDEX reicht docker-compose.yml nicht an die Anwendung weiter; abweichende Werte gehören unter Docker Compose in einer docker-compose.override.yml (siehe Eigene Variablen unter Docker Compose), im Helm-Chart in app.extraEnv.

Volltextsuche

Variable Standard Bedeutung
SEARCH_RANKING v2 v2: alle Wörter müssen vorkommen, Unschärfe nur, wenn fast nichts gefunden wird, begrenzter Aktualitätsbonus. v1: bisherige Abfrage als Rückfall ohne Update (Neustart genügt).
SEARCH_RECENCY_WEIGHT 1.0 Aktualitätsbonus: Neue Treffer zählen höchstens (1 + Wert)-fach; 0 schaltet ihn ab
SEARCH_MIN_RELEVANCE 0.05 Treffer unter diesem Anteil des besten Werts ihres Index entfallen; 0 = alle behalten
SEARCH_NAME_PART_MAX_DOCS 400 Der Namensteil eines Straßennamens (etwa „witzleben“ aus „Witzlebenstraße“) zählt als eigene Lesart nur, wenn höchstens so viele Vorgänge und Dateien der Kommune ihn enthalten
INSIGHT_SEARCH_PLACES true Ortsband im Bürgerportal: erkannte Straße mit den neuesten Vorgängen im Umkreis und Karte, nur aus dem eigenen Straßenverzeichnis
INSIGHT_SEARCH_PLACES_MIN_SHARE 0.5 nur für Kommunen mit mindestens diesem Anteil verorteter Vorgänge
INSIGHT_SEARCH_PLACES_RADIUS 500 Umkreis in Metern

docker-compose.yml reicht alle außer SEARCH_NAME_PART_MAX_DOCS durch.

Worker, Aufträge und Ereignisse

Die Dienste worker, worker-heavy und worker-live führen Aufträge, die Ereignistechnik der Datendrehscheibe und die Zeitpläne aus.

Variable Standard Bedeutung
TASKS_BACKEND immediate immediate: Aufträge laufen sofort in der Anfrage. journal: Aufträge gehen in die Datenbank und laufen im Worker. Erst umschalten, wenn die Worker laufen. Zeitpläne und die Aufträge aus dem Admin laufen in jedem Fall im Worker.
TASKS_MAX_TASKS_PER_PROCESS 1000 Nach so vielen Aufträgen startet der Runner neu
TASKS_MAX_MEMORY_MB 400 Oberhalb dieses Speichers startet der Runner neu; unter der Speichergrenze des Containers halten
EVENTS_WORKER_REQUIRED leer Braucht die Installation einen Worker? Leer: ja, für Zeitpläne und Aufträge, mit Ereignissen der Erzeuger auch für den Sequenzierer. true: alle Rollen. false: keine Meldung; ohne Worker laufen trotzdem keine Zeitpläne. Ohne nötigen Worker melden /health/ und /health/ready/ „degraded“.
EVENTS_SCHEDULES_DISABLED leer einzelne Zeitpläne abschalten, Namen kommagetrennt (siehe Regelmäßige Aufgaben)
EVENTS_DB_DIRECT_URL leer Direktverbindung zu PostgreSQL für den Weckruf der Ereignistechnik, nötig hinter PgBouncer im Transaktionsmodus
INGESTOR_EVENTS_ENABLED false Ingestor und Anwendung melden Änderungen am RIS-Bestand als Ereignisse ins Journal. Erst einschalten, wenn der Worker läuft.
SESSION_EVENTS aus Ereignisse aus mandari Session an die Datendrehscheibe: aus, schatten (Ereignisse werden geschrieben; scheitert das, bleibt die Änderung trotzdem bestehen) oder aktiv (Änderung und Ereignis atomar); je Mandant im Admin überschreibbar
EVENTS_REDACT_NEUTRALIZE false Nach einem Ereignis mit operation=redact personenbezogene Nutzlasten im Journal leeren (DSGVO)
EVENTS_IDEMPOTENCY_RETENTION_DAYS 30 Aufbewahrung der Idempotenzschlüssel der Befehle in Tagen
EVENTS_JOURNAL_PURGE_ENABLED false Journal täglich nach Frist aufräumen; vorher manage.py events_purge --dry-run prüfen
EVENTS_JOURNAL_RETENTION_DAYS 90 Aufbewahrung des Journals in Tagen; mindestens 90 und nie kürzer als OPARL_CHANGES_RETENTION_DAYS
EVENTS_TASKS_DONE_RETENTION_DAYS, EVENTS_TASKS_DEAD_RETENTION_DAYS 14, 90 Aufbewahrung erledigter bzw. toter und fehlgeschlagener Aufträge in Tagen
WORKER_PUSH_URL, WORKER_PUSH_TOKEN leer „Worker lebt“ an einen externen Endpunkt der Statusseite melden
WORKER_PUSH_INTERVAL 60 Abstand dieser Meldungen in Sekunden
WORKER_HEAVY_MEM_LIMIT 3g Speichergrenze des Dienstes worker-heavy (nur Docker Compose)
WORKER_HEAVY_OCR_MEMORY_LIMIT_MB 2048 Adressraum je Tesseract-Prozess in worker-heavy, höchstens Speichergrenze minus 1 GB (nur Docker Compose)
WORKER_SERVICES ingestor minutes-orchestrator worker worker-heavy worker-live Dienste, die update.sh während der Migrationen anhält

docker-compose.yml reicht alle durch außer EVENTS_IDEMPOTENCY_RETENTION_DAYS und WORKER_PUSH_INTERVAL; WORKER_HEAVY_* liest die Compose-Datei selbst, WORKER_SERVICES das Skript update.sh. Im Helm-Chart heißen die wichtigsten events.producers, events.changesFeed, events.journalPurge und worker.*, siehe Betrieb in Kubernetes.

Datendrehscheibe: schrittweise Umstellungen

Diese Schalter stellen einzelne Aufgaben schrittweise auf Ereignisse und Abonnements um. Standard ist überall aus; schatten bzw. probe arbeitet neben dem bisherigen Weg und vergleicht nur. Alle brauchen den Worker; Voraussetzungen und Reihenfolge beim Umschalten beschreibt DEPLOYMENT.md im Repository.

Variable Werte Bedeutung
SEARCH_INDEX_SUBSCRIPTION aus, schatten, aktiv Suchindex aus den Ereignissen; schatten pflegt einen Schattenindex neben dem Live-Index
SEARCH_INDEX_SHADOW_BODIES Kennungen, kommagetrennt Schattenbetrieb nur für diese Kommunen; leer = alle
SEARCH_INDEX_SHADOW_MAX_DOCS Zahl, Standard 100000 ungefähre Obergrenze der Dokumente in allen Schattenindizes; 0 = keine
WORK_NOTIFICATION_SUBSCRIPTION aus, schatten, aktiv Benachrichtigungen in Work über Ereignisse; schatten und aktiv brauchen TASKS_BACKEND=journal
GEOREF_SUBSCRIPTION, SUMMARY_SUBSCRIPTION aus, schatten, aktiv neuer Text eines Dokuments stößt die Verortung seines Vorgangs an bzw. verwirft dessen KI-Zusammenfassung
RIS_SESSION_PROJECTOR aus, schatten RIS-Bestand der Session-Mandanten aus deren Ereignissen, vorerst als unsichtbare Schatten-Quelle
RIS_SESSION_PROJECTOR_TENANTS Kennungen, kommagetrennt nur diese Session-Mandanten; leer = alle
WORK_RIS_RELINK aus, probe, aktiv Notizen, Positionen und Kommentare in Work folgen ihrem Tagesordnungspunkt bzw. ihrer Vorlage, wenn ein RIS seinen Stand neu veröffentlicht; probe meldet nur im Protokoll
WORK_RIS_RELINK_INTERVAL_MINUTES Zahl, Standard 15 Abstand des Abgleichs in Minuten

docker-compose.yml reicht alle durch.

Texterkennung

Variable Standard Bedeutung
TEXT_EXTRACTION_RUNNER ingestor Wer den Text der RIS-Dateien erkennt: ingestor (der Ingestor lädt und erkennt selbst) oder worker (Aufträge im Dienst worker-heavy, die nur aus Ablage und Objektspeicher lesen). worker braucht TASKS_BACKEND=journal, sonst startet die Anwendung nicht. In Anwendung und Ingestor gleich setzen.
TEXT_EXTRACTION_ENABLED True Nur im Ingestor: Volltext aus Dokumenten extrahieren
TEXT_EXTRACTION_MAX_SIZE_MB 50 Größere Dateien werden nicht verarbeitet
TEXT_EXTRACTION_QUEUE_DEPTH 20 Nur mit worker: höchstens so viele Aufträge der Texterkennung warten oder laufen zugleich
TEXT_EXTRACTION_STALE_MINUTES, TEXT_EXTRACTION_MAX_ATTEMPTS 60, 3 Eine Datei, die länger in Bearbeitung ist, gilt als abgebrochen; nach so vielen Abbrüchen als gescheitert
TEXT_EXTRACTION_GIVE_UP_ALERT 5 Die Prüfung „texterkennung“ wird erst ab so vielen aufgegebenen Dateien in 24 Stunden rot
TEXT_EXTRACTION_BACKLOG_ALERT_HOURS 24 Nur mit worker: Die Prüfung „dokumenttext“ wird rot, wenn ein abgelegtes Dokument länger auf seinen Text wartet
OCR_DPI, OCR_MAX_MEGAPIXELS 200, 8 Auflösung der Texterkennung, je Seite gedeckelt
OCR_MEMORY_LIMIT_MB 1024 Adressraum je Tesseract-Prozess. docker-compose.yml setzt 512 für Anwendung und Worker und 384 für den Ingestor, worker-heavy hat WORKER_HEAVY_OCR_MEMORY_LIMIT_MB.
OCR_PAGE_TIMEOUT, OCR_FILE_BUDGET_SECONDS, OCR_MAX_PAGES 120, 1200, 100 Zeitgrenze je Seite, Zeitbudget und Seitenzahl je Datei; danach gilt der bis dahin erkannte Text
MISTRAL_API_KEY, MISTRAL_BASE_URL leer Optionale externe Texterkennung für öffentliche RIS-Dateien. Wirkt nur mit Schlüssel und einer Basis-URL, deren Host in KI_ERLAUBTE_HOSTS steht.
MISTRAL_OCR_MODEL pixtral-12b-2409 Modell des externen Dienstes
MISTRAL_OCR_RATE_LIMIT 60 Anfragen pro Minute an den externen Dienst

Die Erkennung liest zuerst die Textebene des PDFs, dann, falls eingerichtet, den externen Dienst, sonst und als Rückfall die lokale Texterkennung mit Tesseract. docker-compose.yml reicht TEXT_EXTRACTION_RUNNER, TEXT_EXTRACTION_QUEUE_DEPTH, OCR_MEMORY_LIMIT_MB, MISTRAL_API_KEY und MISTRAL_BASE_URL durch, die übrigen nicht. Umstellen auf worker: Ablauf „Dokumentkette einschalten“ in DEPLOYMENT.md im Repository.

KI

Variable Standard Bedeutung
KI_ERLAUBTE_HOSTS leer Positivliste der Hosts, an die KI-Aufrufe gehen dürfen (kommagetrennt, genauer Vergleich, nur HTTPS). Leer = nichts erlaubt, die KI bleibt überall aus. Anbieter, Modell und Schlüssel stehen im Admin unter „KI-Einstellungen“. Gilt auch für den Ingestor.
INSIGHT_CHAT_MAX_TOOL_ROUNDS, INSIGHT_CHAT_TIME_LIMIT_SECONDS 4, 90 KI-Assistent im Bürgerportal: Runden mit Werkzeugen und Zeitlimit je Antwort
INSIGHT_CHAT_DAILY_MAX_CALLS, INSIGHT_CHAT_DAILY_MAX_TOKENS 500, 1000000 Kostenbremse: Tagesobergrenze aller Antworten zusammen; danach bis zum nächsten Tag keine Anfrage
INSIGHT_MCP_ENABLED false öffentlicher, nur lesender MCP-Server unter /insight/mcp
INSIGHT_MCP_PER_IP_MINUTE, INSIGHT_MCP_PER_IP_DAY, INSIGHT_MCP_PER_MINUTE 30, 500, 300 Grenzen je Adresse und Minute, je Adresse und Tag (Werkzeugaufrufe) und insgesamt je Minute; 0 schaltet eine Grenze ab
INSIGHT_MCP_ALLOWED_ORIGINS leer weitere Hosts, deren Browser-Clients zugreifen dürfen

docker-compose.yml reicht alle durch.

OParl-Aggregations-API

Variable Standard Bedeutung
OPARL_BASE_URL SITE_URL + /oparl Basis aller Objekt-IDs. Erlaubt die Auslieferung unter einer eigenen Subdomain.
OPARL_API_PAGE_SIZE 100 Objekte pro Listenseite, gilt auch für die Session-OParl-API
OPARL_API_RATE_LIMIT 120 Anfragen pro Minute je IP-Adresse, 0 deaktiviert das Limit
OPARL_API_CACHE_SECONDS 60 Cache-Dauer ungefilterter Listenseiten
OPARL_LICENSE_URL leer Lizenz am System-Objekt des Aggregators; leer = es gilt die Lizenz der Kommune
OPARL_CHANGES_ENABLED false Änderungsfeed und Snapshot je Kommune. Erst einschalten, wenn die Erzeuger laufen (INGESTOR_EVENTS_ENABLED=true, Worker), sonst täuschte ein leerer Feed vor, es habe sich nichts geändert.
OPARL_CHANGES_RETENTION_DAYS 90 Gültigkeit eines Cursors in Tagen, mindestens 30
OPARL_SNAPSHOT_PARALLEL 2 gleichzeitig entstehende Snapshots; weitere Anfragen erhalten 503 mit Retry-After

docker-compose.yml reicht nur OPARL_CHANGES_ENABLED, OPARL_CHANGES_RETENTION_DAYS und OPARL_SNAPSHOT_PARALLEL durch. Fehler des Änderungsfeeds beschreibt Fehlertypen der Schnittstellen.

Offene Daten und Suchmaschinen

Variable Standard Bedeutung
DCAT_ENABLED false Katalog der offenen Ratsinformationen nach DCAT-AP.de unter /data/dcat/ und je Session-Mandant. Erst einschalten, wenn Herausgeber und Kontakt stimmen.
DCAT_PUBLISHER_NAME, DCAT_PUBLISHER_URL mandari, SITE_URL Herausgeber der Datensätze des Aggregators (der Betreiber, keine Person) und seine Webseite
DCAT_CONTACT_EMAIL leer Funktionspostfach als Kontakt im Katalog
DCAT_CONTRIBUTOR_ID leer Kennung des Betreibers bei GovData
DCAT_CACHE_SECONDS 300 fertige Kataloge im Cache; 0 = aus
INDEXNOW_KEY leer Meldet neue, geänderte und entfernte Seiten des Bürgerportals über IndexNow an Suchmaschinen (nur öffentliche Adressen). 8 bis 128 Zeichen aus Buchstaben, Ziffern und -. Braucht den Worker und INGESTOR_EVENTS_ENABLED=true.
INDEXNOW_ENDPOINT https://api.indexnow.org/indexnow Adresse der Meldungen

docker-compose.yml reicht nur INDEXNOW_KEY durch, an Anwendung, Worker und Website.

Dokument-Cache und Quellen-Schonung

Variable Standard Bedeutung
OPARL_FILES_ROOT <MEDIA_ROOT>/oparl_files Wurzelverzeichnis des Caches, im Container /app/files
FILE_CACHE_MAX_MB 80 Größere Dateien werden nicht gecacht, aber durchgereicht
FILE_CACHE_MIN_FREE_GB 15 Unter dieser Grenze freien Speichers wird nichts mehr geschrieben
FILE_PROXY_TIMEOUT_SECONDS 15 Lese-Timeout für Live-Abrufe bei der Quelle
RIS_REQUEST_INTERVAL 1.0 Abstand je Server in Sekunden für alle Abrufe der Anwendung (gemeinsamer Takt über Redis); 0 schaltet die Drossel ab, nur für Tests und Notfälle
INSIGHT_SOURCE_BACKOFF_FAILURES 3 Ab so vielen fehlgeschlagenen Läufen des Abgleichs in Folge ruhen Dokument-Cache, Vorschau, Löschabgleich und Personenfotos für die Quelle

FILE_CACHE_MAX_MB, FILE_PROXY_TIMEOUT_SECONDS, RIS_REQUEST_INTERVAL und INSIGHT_SOURCE_BACKOFF_FAILURES reicht docker-compose.yml nicht durch. Tragen Sie sie unter Docker Compose in x-app-environment ein, im Helm-Chart in app.extraEnv; ein Eintrag nur in der .env wirkt nicht.

Details unter Dokument-Cache.

Dokumentablage und Objektspeicher

Variable Standard Bedeutung
FILE_STORE_LAYOUT sha256 Ablage nach SHA-256 mit Referenzzählung; kommune behält das ältere Verzeichnis je Kommune, ohne Deduplizierung und ohne Objektspeicher
INGESTOR_STORES_FILES false (docker-compose.yml: true) Der Ingestor legt Dateien, die er für den Text lädt, selbst in der Ablage ab; der Dokument-Cache holt sie dann nicht noch einmal
FILE_CACHE_MAX_TOTAL_GB 0 Obergrenze der Gesamtgröße in GB, 0 = unbegrenzt. Darüber verdrängt das stündliche Aufräumen die am wenigsten gebrauchten Dokumente.
FILE_CACHE_EVICT_TARGET_PERCENT 90 so weit unter die Obergrenze räumt das Aufräumen
FILE_ACCEL_REDIRECT false Dokumente liefert Caddy aus statt Django (Range, ETag). Voraussetzung: Caddyfile und Volume aus docker-compose.yml, sonst kommen leere Antworten an.
FILE_PROXY_PACE_MAX_WAIT_SECONDS 5 So lange wartet die Vorschau höchstens auf einen Abrufplatz bei der Quelle, sonst bittet sie um einen neuen Versuch
FILE_PURGE_AFTER_DAYS 30 Löschabgleich: Kopie und Text eines gesperrten Dokuments nach so vielen Tagen löschen
FILE_PURGE_CONFIRM_GRACE_DAYS 7 so viele Tage zusätzlich, wenn sich die Quelle vor dem Löschen nicht befragen lässt
FILE_RECONCILE_MAX_MISSING 10 Bremse: Melden in einem Lauf mehr Dokumente einer Quelle neu 404 oder 410, wird keines gesperrt
DOCUMENT_FETCH_STALE_MINUTES, DOCUMENT_FETCH_MAX_QUEUED 30, 200 Ein Abruf beansprucht seine Datei höchstens so lange; je Quelle und Lauf höchstens so viele Abrufe
DOCUMENT_FETCH_RETRY_ALERT_HOURS 6 Die Prüfung „dokumentabruf“ wird rot, wenn fällige Wiederholungen länger liegen
INSIGHT_FETCH_ALLOW_PRIVATE_NETWORKS false Dokumente auch von Adressen im internen Netz abrufen; nur für ein Ratsinformationssystem im Intranet
OBJ_ENABLED false S3-kompatibler Objektspeicher für die Ablage; die lokale Ablage wird dann zum Zwischenspeicher. Erst einschalten, wenn dokumentablage --umstellen durchgelaufen ist.
OBJ_ENDPOINT, OBJ_BUCKET, OBJ_REGION leer Adresse, Bucket und Region
OBJ_KEY, OBJ_SECRET leer Zugangsdaten, nie im Repository
OBJ_CACHE_MAX_GB 60 Größe des lokalen Zwischenspeichers
OBJ_CHECKSUMS when_required Prüfsummen beim Hochladen: when_required (verträglich mit S3-kompatiblen Anbietern) oder when_supported
OBJ_ADDRESSING_STYLE, OBJ_TIMEOUT_SECONDS, OBJ_FETCH_TOTAL_SECONDS auto, 30, 60 Adressierung, Zeitgrenze je Anfrage und Gesamtdauer eines Abrufs aus dem Objektspeicher

docker-compose.yml reicht FILE_STORE_LAYOUT, INGESTOR_STORES_FILES, FILE_CACHE_MAX_TOTAL_GB, FILE_CACHE_EVICT_TARGET_PERCENT, FILE_ACCEL_REDIRECT, INSIGHT_FETCH_ALLOW_PRIVATE_NETWORKS sowie OBJ_ENABLED, OBJ_ENDPOINT, OBJ_BUCKET, OBJ_KEY, OBJ_SECRET, OBJ_REGION, OBJ_CACHE_MAX_GB und OBJ_CHECKSUMS durch, die übrigen nicht. Die Zugangsdaten des Objektspeichers können auch in einer eigenen Umgebungsdatei liegen: docker compose --env-file .env --env-file <datei> up -d.

Quellenüberwachung

Variable Standard Bedeutung
INSIGHT_SOURCE_STALE_WARNING_HOURS 48 Ab diesem Alter des letzten Syncs: Warnung
INSIGHT_SOURCE_STALE_CRITICAL_DAYS 7 Ab diesem Alter: kritisch, Alarm-E-Mail

Details unter Betriebsmonitor.

Betriebsprüfungen und Metriken

Variable Standard Bedeutung
METRICS_ALLOWED_NETWORKS Loopback und private Netze Der Endpunkt /metrics/ antwortet nur diesen Netzen (CIDR, kommagetrennt) oder mit Token, sonst 404
METRICS_TOKEN leer Bearer-Token für /metrics/ von außerhalb dieser Netze
METRICS_URL http://127.0.0.1:8000/metrics/ (docker-compose.yml: http://mandari:8000/metrics/) Woher die Prüfung der Service-Level im Worker die Metriken der Anwendung holt; leer = Fehlerquote nicht prüfen
GATUS_URL leer Statusseite (Gatus) für den monatlichen Verfügbarkeitsbericht; ohne sie gibt es den Zeitplan nicht
SERVICE_LEVEL_DISK_MIN_FREE_PERCENT, SERVICE_LEVEL_DISK_MIN_FREE_GB 10, 2 Alarm bei weniger freiem Plattenplatz
SERVICE_LEVEL_TLS_MIN_DAYS 14 Alarm, wenn ein Zertifikat früher abläuft
SERVICE_LEVEL_ERROR_RATE_MAX_PERCENT, SERVICE_LEVEL_ERROR_RATE_MIN_REQUESTS 1, 100 Alarm bei höherer Fehlerquote, gerechnet ab so vielen Anfragen
SERVICE_LEVEL_QUEUE_MAX_AGE_MINUTES 120 Alarm, wenn ein Auftrag länger wartet
MONITOR_TLS_HOSTS leer weitere Hosts, deren Zertifikat geprüft wird; SITE_URL immer
HEALTH_READY_OPTIONAL leer Prüfungen, die /health/ready/ meldet, ohne deshalb 503 zu antworten, zum Beispiel elasticsearch
REPORTS_ROOT <MEDIA_ROOT>/berichte Ablage der Berichte, etwa des Verfügbarkeitsberichts; nie über /media/ abrufbar
LOG_FORMAT, LOG_LEVEL, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_SERVICE_NAME siehe Logging und Tracing

Die Alarme gehen an INSIGHT_ALERT_EMAILS. docker-compose.yml reicht nur METRICS_URL und GATUS_URL durch.

Bürgerportal

Variable Standard Bedeutung
INSIGHT_SUBSCRIPTIONS_ENABLED false Abos zu Themen und Orten (/insight/benachrichtigungen/); eingeschaltet laufen die Zeitpläne generate_alerts und send_digest. Beschluss-Abos sind davon unabhängig.
INSIGHT_QUESTIONS_ENABLED false Ratsfragen (/insight/fragen/); aus heißt pausiert: Bisherige Fragen bleiben lesbar, neue sind nicht möglich, es gehen keine Mails hinaus
INSIGHT_DIGEST_ENABLED true Versand der Wochenmail durch send_digest
INSIGHT_DIGEST_MAX_ALERTS_PER_MAIL 20 Höchstzahl der Meldungen je Wochenmail
GEOREF_ENABLED true Verortung von Vorlagen insgesamt
GEOREF_AUTO_ENABLED, GEOREF_AUTO_LIMIT, GEOREF_AUTO_INTERVAL_MINUTES true, 50, 15 automatischer Verortungslauf als Zeitplan: an oder aus, Vorlagen je Lauf, Abstand in Minuten
GEOREF_TEXT_MAX_CHARS 8000 Kürzung des Textes für die Verortung über KI und Photon
PHOTON_API_URL, GEOCODING_RATE_LIMIT https://photon.komoot.io/api/, 5 Geocoding-Dienst und Anfragen je Sekunde, etwa für die Nachbarschaftssuche
MAP_MARKERS_CACHE_SECONDS 600 Cache der Kartenmarker

docker-compose.yml reicht nur INSIGHT_SUBSCRIPTIONS_ENABLED und INSIGHT_QUESTIONS_ENABLED durch.

Session, Work und Protokollierung

Variable Standard Bedeutung
SESSION_PACKAGE_MAX_EMBED_MB, SESSION_PACKAGE_MAX_PAGES 200, 3000 Obergrenzen der PDF-Anlagen im Gesamt-PDF einer Sitzungsmappe; weitere erscheinen als Verweisseite, im ZIP-Paket bleiben alle
AUDIT_ARCHIVE_ROOT <MEDIA_ROOT>/audit_archive Archivpakete vor der fristgerechten Löschung; nie über /media/ abrufbar
AUDIT_ARCHIVE_STORAGE leer statt des Verzeichnisses ein Speicher aus STORAGES, etwa ein S3-Speicher
AUDIT_EXPORT_MAX_ROWS 100000 Obergrenze eines Exports des Prüfprotokolls aus der Oberfläche; größere Zeiträume mit manage.py export_audit_log
SECURITY_AUDIT_RETENTION_DAYS 365 Aufbewahrung des Sicherheitsprotokolls in Tagen
FACTION_SCHEDULE_INTERVAL_MINUTES, FACTION_SCHEDULE_HORIZON_DAYS 60, 90 Work: Fraktionssitzungen aus Sitzungsreihen; Abstand des Laufs in Minuten und Zeitraum in Tagen, für den Sitzungen im Voraus entstehen

docker-compose.yml reicht keine davon durch.

Live-Übertragungen

Variable Standard Bedeutung
LIVE_UEBERTRAGUNG_AKTIV false Status der Streaming-Anbieter rund um die Sitzungen abfragen und während der Übertragung Tagesordnungspunkt und Namen aus Einzelbildern lesen (nur im Speicher). Aus: keine Anfragen nach außen, kein Zeitplan. An: Dienst worker-live muss laufen.
LIVE_PROTOKOLL_TAGE 90 Aufbewahrung des Protokolls in Tagen
LIVE_TESSERACT_CMD, LIVE_TESSDATA_DIR tesseract, leer Programm und Sprachdaten der Texterkennung
LIVE_OCR_MEMORY_LIMIT_MB, LIVE_OCR_TIMEOUT_SECONDS 256, 20 Speicher- und Zeitgrenze je Erkennung

docker-compose.yml reicht LIVE_UEBERTRAGUNG_AKTIV und LIVE_PROTOKOLL_TAGE durch, im Helm-Chart heißt der Schalter liveStreams.enabled.

Ingestor

Variable Standard Bedeutung
INGESTOR_INTERVAL 10 (.env.example, install.sh und Helm: 15) Grundtakt je Quelle werktags 7–19 Uhr in Minuten; sonst stündlich, am Wochenende alle 2 Stunden, an Sitzungstagen und am Vortag (7–22 Uhr) alle 5 Minuten, nach Abgleichen ohne Änderung seltener; je Quelle einstellbar (siehe Takt und Vollabgleich je Quelle)
INGESTOR_FULL_SYNC_HOUR 3 Beginn des nächtlichen Standardfensters für Vollabgleiche (5 Stunden, Ortszeit) für Quellen ohne eigenes Zeitfenster; Werte außerhalb von 0 bis 23 schalten geplante Vollabgleiche ab, auch in eigenen Zeitfenstern der Quellen; im Admin angeforderte bleiben möglich
INGESTOR_CONCURRENT 10 Abrufplätze je Quelle; je Server gilt trotzdem INGESTOR_HOST_MAX_CONCURRENT
INGESTOR_SYNC_POOL_SIZE 4 Quellen, die der Ingestor gleichzeitig abgleicht, je Quelle höchstens ein Lauf; Vollabgleiche belegen höchstens alle Plätze bis auf einen
INGESTOR_MEM_LIMIT 512m Speichergrenze des Ingestor-Containers (nur Docker Compose)
INGESTOR_REQUEST_INTERVAL 1.0 Abstand je Server in Sekunden (gemeinsamer Takt über Redis); 0 schaltet die Drossel ab, nur für Tests und Notfälle
INGESTOR_HOST_MAX_CONCURRENT 2 Offene Anfragen je Server und Prozess; 0 = ohne Grenze
INGESTOR_USER_AGENT (älter: SCRAPER_USER_AGENT) mandari-ingestor/<Version> (+https://mandari.de/ingestor/; support@mandari.de) User-Agent des Ingestors (Abgleich, Scraper, Texterkennung, Sondierung)
SCRAPER_TOMBSTONE_FULL_CRAWLS 3 Nach so vielen Voll-Crawls ohne Sichtung gilt ein Objekt als gelöscht
SCRAPER_PARSE_QUOTA_WARN 0.8 Warnung, wenn weniger als dieser Anteil der Seiten geparst werden konnte

INGESTOR_INTERVAL, INGESTOR_FULL_SYNC_HOUR, INGESTOR_CONCURRENT, INGESTOR_SYNC_POOL_SIZE und INGESTOR_MEM_LIMIT liest docker-compose.yml aus der .env; im Helm-Chart heißen die ersten drei ingestor.syncInterval, ingestor.fullSyncHour und ingestor.concurrent, INGESTOR_SYNC_POOL_SIZE gehört dort in ingestor.extraEnv. Die übrigen Variablen der Tabelle reicht es nicht durch: Tragen Sie sie unter Docker Compose im Abschnitt environment des Dienstes ingestor ein, im Helm-Chart in ingestor.extraEnv; ein Eintrag nur in der .env wirkt nicht. Die Sync-Aktionen an einer Quelle im Admin gehen an den Ingestor, solange er läuft; ohne ihn und für abgeschaltete Quellen laufen sie im Worker der Anwendung. Setzen Sie INGESTOR_USER_AGENT, INGESTOR_REQUEST_INTERVAL und INGESTOR_HOST_MAX_CONCURRENT deshalb auch dort, unter Docker Compose in x-app-environment, im Helm-Chart in app.extraEnv; sonst ruft der Worker mit der Standardkennung samt support@mandari.de ab.

Details unter Quellen anbinden, Regeln für den Abruf unter Ingestor und Opt-out.