Нет описания

gc-server3 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
.vscode 444a303300 Kleine Anpassungen 1 месяц назад
app 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
migrations 6cf42fec89 Füge Authentifizierungs- und Berechtigungsmanagement hinzu 1 месяц назад
static 0158a876f8 Füge Dashboard-Funktionalität hinzu und entferne veraltete SQL-Abfragen 1 неделя назад
templates 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
tests 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
webservice 39f9011c2a Logging 1 неделя назад
.env.example 39f9011c2a Logging 1 неделя назад
.gitignore 6cf42fec89 Füge Authentifizierungs- und Berechtigungsmanagement hinzu 1 месяц назад
.python-version ba4f1437b4 init 9 месяцев назад
README.md 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
filter_export.py 39f9011c2a Logging 1 неделя назад
pyproject.toml 39f9011c2a Logging 1 неделя назад
server.py 82839ae76b Projekt an die Reisacher-Datenbank angepasst 1 неделя назад
specs.md 2fac46b3d9 Verschiedene Verbesserungen an der Dokumentation und den SQL-Modellen 9 месяцев назад
tox.ini dfc1615049 Erster Entwurf von GPT-5 mini 9 месяцев назад
uv.lock 39f9011c2a Logging 1 неделя назад

README.md

GlobalCube Enterprise Planning, Information & Controlling (gcepic)

Das ultimative Tool für:

  • Forderungsmanagement
  • Offene Aufträge
  • Planung
  • Fahrzeug-Auftragseingang

Installation

Zunächst muss uv, der Python-Paketmanager, installiert werden:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Im Anschluss git-Repository klonen (am Beispiel von Ordner C:\Projekte - im Grunde beliebig):

cd C:\Projekte
git clone https://git.global-cube.com/GlobalCube/Reisacher-Forderung.git

Git erstellt einen Unterordner C:\Projekte\Reisacher-Forderung, in dem das gesamte Projekt abgelegt ist. Jetzt müssen alle Requirements erfüllt werden: passende Python-Version, benötigte Module mit entsprechenden Abhängigkeiten. Das übernimmt uv

Konfiguration

cd C:\Projekte\Reisacher-Forderung
uv sync
copy .env.example .env

Danach müssen in .env die Datenbank-, LDAP-, Proxy- und JWT-Platzhalter ersetzt werden.

Danach kann der Webserver gestartet werden:

.venv\Scripts\activate.bat
uvicorn app.main:app --reload --host 0.0.0.0 

Die Konsole meldet dann Folgendes:

(Reisacher-Forderung) PS C:\Projekte\Reisacher-Forderung> uvicorn app.main:app --reload --host 0.0.0.0                                
INFO:     Will watch for changes in these directories: ['C:\\Projekte\\Reisacher-Forderung']
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [41364] using WatchFiles
INFO:     Started server process [23216]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Das Repository ist nun bereit für die Nutzung.

Nutzung

Öffne http://127.0.0.1:8000 im Browser.

Authentifizierung und Deployment

Die Anwendung läuft im Produktivbetrieb ausschließlich hinter dem IIS-Reverse-Proxy auf 127.0.0.1:8094. IIS entfernt einen eventuell vom Client gelieferten Header X-Remote-User und setzt ihn nur für erfolgreich per Windows Authentication bestätigte Benutzer neu. Fehlt der Header, bietet die Anwendung die Anmeldung gegen Active Directory über LDAPS an.

  1. migrations/001_authentication.sql auf der Anwendungsdatenbank ausführen.
  2. .env.example nach .env kopieren und alle Platzhalter ersetzen.
  3. Ein eigenes zufälliges JWT_SECRET mit mindestens 32 Byte konfigurieren.
  4. Das LDAPS-Zertifikat des Domain Controllers auf dem Server als vertrauenswürdig installieren.
  5. Die IIS-Proxyadresse in TRUSTED_PROXY_IPS eintragen und den FastAPI-Port nicht extern freigeben.
  6. Den Windows-Dienst mit webservice/install_service.bat installieren.

Die Rollenprioritäten sind: Buchhaltung (400), Standortleitung (300), Abteilungsleitung (200) und Mitarbeiter (100). Berechtigungen werden bei jedem Request aus dbo.Benutzer_Rechte gelesen; leere Benutzerkennungen erteilen keine Rechte.

Tests werden ohne zusätzliche Testabhängigkeiten ausgeführt:

.venv\Scripts\python.exe -m unittest discover -v

Filter auf der Forderungsdetailseite

Kommentare und Buchungsbelege starten jeweils mit „Diese Rechnung“ und lassen sich unabhängig auf offene Rechnungen, das Fahrzeug oder die gesamte Debitorhistorie erweitern. Die Auswahl gilt für die geöffnete Seite und wird beim Neuladen zurückgesetzt. Die Fahrzeugansicht bleibt auf denselben Debitor begrenzt und ist ohne Fahrzeugnummer deaktiviert. Offen bedeutet Beleg_Offen <> 0; Zahlungen werden über Bezug_Beleg_Nr zugeordnet.

Alle Filter bleiben im Mandanten der Ausgangsrechnung. Nach erfolgreicher Rechteprüfung dieser Rechnung umfasst die erweiterte Ansicht ausdrücklich auch andere Standorte und Abteilungen des Debitors. Der direkte Zugriff auf andere Rechnungen wird separat geprüft. Neue Kommentare gehören immer zur geöffneten Rechnung, auch in erweiterten Ansichten. Filterwechsel erhalten ungespeicherte Eingaben. Buchungsbelege sind auf 1.000 Zeilen begrenzt; bei Erreichen dieses Limits erscheint ein Hinweis.

Die lesenden Endpunkte /app/forderungen/details/{primary_key}/kommentare und /app/forderungen/details/{primary_key}/buchungen liefern HTML-Fragmente für HTMX. scope akzeptiert invoice (Standard), open, vehicle und debtor; andere Werte werden mit HTTP 422 abgelehnt. Kommentar-POSTs übergeben die aktuelle Auswahl als comment_scope. Datenbankschemaänderungen sind nicht erforderlich.

Debug-Anmeldung ohne LDAP

Für Entwicklung und manuelle Tests diese Werte in .env setzen und die Anwendung neu starten:

ENVIRONMENT=development
DEBUG_AUTH=true
COOKIE_SECURE=false

Unter /login dieselbe Benutzerkennung in beide Felder eingeben, z. B. Benutzername winter und Passwort winter. Beide Eingaben müssen exakt übereinstimmen. Die Kennung wird anschließend wie beim AD-Login normalisiert. Eine gültige Zuordnung in dbo.Benutzer_Rechte zu einer aktiven Rolle in dbo.Rollen ist weiterhin erforderlich; mehrere Berechtigungszeilen werden wie bisher vereinigt. Ein LDAP-Server ist dafür nicht nötig, die konfigurierte SQL-Datenbank und die Authentifizierungsmigration hingegen schon.

Im Debugmodus werden IIS-Identitätsheader ignoriert, damit verschiedene Benutzer über das Formular getestet werden können. JWT, CSRF, Logout und die Rechteprüfung pro Request bleiben aktiv; der Token enthält auth_source=debug. Benutzername wird als Anzeigename verwendet, E-Mail bleibt leer. Nach dem Deaktivieren von DEBUG_AUTH werden diese Tokens nicht mehr akzeptiert. Standardmäßig ist DEBUG_AUTH=false; außerhalb der Umgebungen development, debug und test verweigert die Anwendung den Start mit aktivem Debug-Login. COOKIE_SECURE=false ist nur für lokale HTTP-Tests gedacht; bei HTTPS auf true setzen.

Forderungsdashboard

Das Dashboard verwendet dieselbe berechtigte Belegabfrage wie die Liste. Anzahl und Beleg_Offen enthalten auch Gutschriften, negative Beträge und Nullbeträge; jeder Beleg wird anhand von Mandant und Belegnummer einmal gezählt. Die Berechtigungsprüfung erfolgt vor der Aggregation über Benutzer, Hauptbetrieb, Standort und Abteilung. Beträge werden mit Dezimalarithmetik summiert. An den Browser gehen nur berechtigte Aggregate.

Die Rubriken Altersstaffel, Standort und Verursacher zeigen horizontale Balken mit Umschalter zwischen Betrag und Anzahl. Die Stapelung lässt sich zwischen Abteilung und Wiedervorlage wählen (stack=abteilung|wiedervorlage). Negative Beträge liegen links der Null. Verursacherüberschreibungen und die effektive Wiedervorlage werden wie in der Liste berücksichtigt. Für die Staffelung gilt zuerst Forderungen_Details.Wiedervorlage, ersatzweise Beleg_Faellig_Datum. Maßgeblich ist der Berliner Kalendertag: „Überfällig“ liegt vor heute, „In 3 Tagen fällig“ umfasst heute bis heute + 3 Tage, „Noch nicht fällig“ heute + 4 bis einschließlich heute + 14 Tage und „zurückgestellt“ alles danach. Fehlen beide Datumsfelder, bleibt der Beleg separat als „Ohne Datum“ sichtbar. Die verwendeten Datumsgrenzen stehen konkret im Listenlink und wandern nicht nachträglich. Alte Dashboardadressen mit page=Wiedervorlage wechseln zum Standort mit Wiedervorlagestapelung; bestehende Listenlinks bleiben gültig.

Mouseover zeigt beide Kennzahlen für Segment und Gruppe; Antippen fixiert die Anzeige, Escape schließt sie. „Liste öffnen“ startet einen neuen Tab. Die aufklappbare Datentabelle bietet dieselben Werte und Links per Tastatur, auch für Beträge von null Euro. Suche und Diagrammseiten mit jeweils 20 Gruppen ändern nicht die Gesamtkennzahlen. page=Altersstaffel|Standort|Verursacher, metric=betrag|anzahl und stack bestimmen die initiale Ansicht; Standard ist „Nach Standort“. Chart.js 4.6.1 wird erst beim Dashboardaufruf geladen; bei einem Ladefehler bleibt die Datentabelle verfügbar. Es gibt keine neuen Schreibaktionen.

Die standardmäßig ausgeschaltete Checkbox „Nur Rechnungen“ (only_invoices=true) begrenzt Kennzahlen, Diagramme und Datentabelle exakt auf Rechnung_Gutschrift = 'Rechnung'. Rechnungen mit negativem oder null offenem Betrag bleiben enthalten. Die Auswahl bleibt bei Rubrik- und Kennzahlwechseln sowie beim Neuladen erhalten und gilt auch für sämtliche verlinkten Listen; deren Dashboardfilter trägt dafür das boolesche Feld only_invoices.

Der zusätzliche Listenparameter dashboard_segment enthält eine URL-kodierte JSON-Auswahl mit view, key und optional department beziehungsweise follow_up mit konkreten Datumsgrenzen. Gruppen werden exakt mit gebundenen Parametern gefiltert; fehlende Werte stehen ausdrücklich als null. Ungültige Auswahlen werden mit HTTP 400 abgelehnt. Normale Listenfilter wirken zusätzlich und behalten ihre bisherige Teiltextsuche. Der Dashboardfilter zählt als ein aktiver Filter, ist separat entfernbar und bleibt bei Nachladen, Detailnavigation, Rückkehr, Bearbeitungsmodals und Login erhalten.

Darstellung der Forderungsliste

Die Filter bleiben vollständig sichtbar und sind in Organisation, Kunde und Beleg sowie Bearbeitung und Wiedervorlage gegliedert. Beim Scrollen der Seite dockt der Tabellenkopf unter der Navigation an; bei schmalen Fenstern lässt sich die Tabelle seitlich verschieben. Kommentare und Antragsinformationen werden je Beleg über „Anzeigen“ eingeblendet.

Die Fußleiste zeigt Anzahl und offenen Gesamtbetrag aller gefilterten Treffer, unabhängig von den bereits nachgeladenen Zeilen. Aktive Filter lassen sich dort aufklappen. Auch ohne Treffer bleiben die Filter bedienbar. Die gemeinsamen Gestaltungsregeln liegen in app.css, die Ansichten ergänzen list.css beziehungsweise details.css.

Rückkehr aus der Detailseite und erneute Anmeldung

„Zurück“, „Speichern & Zurück“ und Browser-Zurück laden die Liste frisch, behalten die Filter und führen zur zuvor geöffneten Rechnung. Dazu wird auf der Detailseite eine validierte Listenadresse in return_to und auf der Liste die Belegkennung in focus mitgeführt. Liegt der Beleg hinter dem ersten Nachladeblock, liefert der erste Aufruf die Zeilen bis einschließlich seines Blocks; danach läuft das Nachladen normal weiter. Ist der Beleg nicht mehr enthalten, bleiben die Filter bestehen und ein Hinweis erscheint. Der Browser hält Rückkehrkontexte getrennt je Tab und Benutzer; es werden keine Kommentare oder Formulareingaben im Browserspeicher abgelegt.

Bei abgelaufener Anmeldung führen HTMX-Anfragen nach dem Login auf die vollständige gefilterte Liste beziehungsweise Detailseite. Kommentar- und Buchungsfragmente sowie technische Nachladeseiten sind keine Login-Rücksprungziele. Unterbrochene Schreibaktionen werden nicht automatisch wiederholt; ungespeicherte Eingaben werden nicht gesichert.

Verursacher ändern

Der Stift neben dem Verursacher öffnet in Liste und Detailseite dasselbe Auswahlmodal. Die Benutzer stammen aus dbo.Benutzer_Rolle (Benutzer_ID, Name, Rolle_Name) und lassen sich nach Rolle filtern. Mehrere Rollen erzeugen keine doppelten Benutzer oder Rechnungszeilen. Jeder Benutzer mit Belegzugriff darf die Zuordnung ändern.

Gespeichert wird ausschließlich dbo.Forderungen_Details.Verursacher_Benutzer_ID. „Auf ursprünglichen Verursacher zurücksetzen“ entfernt diese Überschreibung. Auf der Detailseite steht die aktuelle Zuordnung im Bereich „Bearbeitung“ oberhalb der Wiedervorlage; in den Grunddaten bleibt der ursprüngliche Verursacher sichtbar. Das Modal speichert unabhängig vom übrigen Formular und erhält dessen ungespeicherte Eingaben sowie Kommentarentwürfe. Die normalen Speicherbuttons ändern diese Zuordnung nicht. In der Liste führt das Speichern zu einem frischen Aufruf mit denselben Filtern und Fokus auf die Rechnung; entfällt sie durch die Filter, erscheint ein Hinweis.

Bei abgelaufener Anmeldung wird nach dem Login die vollständige Liste beziehungsweise Detailseite geöffnet. Eine unterbrochene Zuordnungsänderung wird nicht automatisch wiederholt. Es sind keine neuen Datenbanktabellen oder Migrationen erforderlich.

Wiedervorlage in der Liste ändern

Das Wiedervorlagedatum ist ein Button mit einem Datumsmodal. „Heute“ und „Heute + 7 Tage“ setzen das Eingabefeld anhand des aktuellen Datums in Europe/Berlin; erst „Speichern“ übernimmt die Änderung. Ein fehlendes Datum lässt sich über „Festlegen“ ergänzen. Die Änderung schreibt ausschließlich Forderungen_Details.Wiedervorlage und den Kommentar WV auf dd.mm.yyyy angepasst mit dem angemeldeten Benutzer und Berliner Zeitstempel. Datum und Kommentar werden gemeinsam in einer Transaktion gespeichert. Ein unverändertes Datum erzeugt keinen weiteren Kommentar. Danach wird die Liste mit den bestehenden Filtern frisch geladen und die Rechnung fokussiert; passt sie nicht mehr zum Filter, erscheint der entsprechende Hinweis. Nach einem Login wird ein unterbrochener Speichervorgang nicht automatisch wiederholt.

Dokumente im Kommentarbereich

Über die Büroklammer oder durch Ablegen auf dem Kommentarfeld können mehrere Dateien beliebigen Typs ausgewählt werden. Die Auswahl mit Name, Größe und Entfernen-Schaltfläche bleibt bis „Abschicken“ ausschließlich im Browser. Kommentartext ist optional; reine Datei-Uploads erzeugen keinen Chat-Eintrag. Beim Verlassen oder Neuladen geht eine noch nicht abgeschickte Auswahl verloren.

LOCAL_STORAGE="C:\\Projekte\\Reisacher-Fileserver"
UPLOAD_MAX_FILE_SIZE_MB=50

Die Größenbegrenzung gilt je Datei, einschließlich leerer Dateien: 50 MB entsprechen 50 × 1024² = 52.428.800 Bytes. Auswahl und Server prüfen die Grenze. Neue Dateien liegen unter LOCAL_STORAGE/{Client_DB}_{Beleg_Nr}/{Originalname}. Altdateien unter LOCAL_STORAGE/{Client_DB}/{Beleg_Nr} bleiben sichtbar und herunterladbar; es gibt keine Migration. Unicode-Namen bleiben erhalten. Unter Windows unzulässige Dateinamen werden mit einer Fehlermeldung abgelehnt.

Bei Namenskonflikten in beiden Belegordnern wird die ältere Datei in ihrem jeweiligen Ordner als Name_YYYYMMDD_HHMMSS_ffffff.ext archiviert (Europe/Berlin, bei Bedarf mit Zähler). Eine prozessübergreifende Belegsperre unter .upload-locks schützt die Ablage auch bei mehreren Workern. Dateien werden zuerst unter .upload-staging vollständig geschrieben und geprüft; danach erfolgt die Übernahme mit Rücknahme der Archivierung, wenn diese Datei nicht abgelegt werden kann. Diese internen Ordner sind über die Downloadroute nicht erreichbar. Der Ablagepfad darf nicht als öffentliches IIS-Verzeichnis oder als statischer Webpfad freigegeben werden.

Das Anwendungskonto benötigt Lesen, Auflisten, Anlegen, Schreiben, Umbenennen und Löschen im Ablagestamm, beiden Belegstrukturen sowie den internen Arbeitsordnern. Für diese Ordner nur den erforderlichen Betriebskonten Zugriff geben. Alle Worker müssen denselben Stamm mit funktionierenden Dateisperren verwenden. Downloads prüfen weiterhin die Belegrechte.

Erfolgreiche Dateien bleiben bei Teilerfolgen oder fehlgeschlagener Kommentarspeicherung bestehen. Nur fehlgeschlagene Dateien und nicht gespeicherter Text bleiben zur erneuten Übermittlung in der Auswahl. Nach einer erneuten Anmeldung werden Uploads nicht automatisch wiederholt. Kommentarhistorie und Dateiliste aktualisieren sich ohne Seitenneuladen.

Bei IIS system.webServer/security/requestFiltering/requestLimits/maxAllowedContentLength (in Bytes) sowie gegebenenfalls vorgeschaltete Proxy- und Hosting-Limits auf die gesamte Multipart-Anfrage abstimmen: Anzahl gleichzeitig versandter Dateien × Dateilimit plus Kommentar und Multipart-Overhead. Das Dateilimit ist kein Gesamtlimit. Beispielsweise brauchen vier Dateien à 50 MB mehr als 209.715.200 Bytes; 220.200.960 Bytes (210 MiB) lassen hierfür zusätzlichen Overhead zu. Das übliche IIS-Standardlimit von 30.000.000 Bytes reicht bereits für eine 50-MB-Datei nicht aus. Eine serverseitig mit 413 abgewiesene Anfrage bleibt in der Auswahl; dann weniger Dateien gleichzeitig senden oder das Betriebslimit anpassen. Genügend temporären Speicher auch für den Multipart-Parser des Servers einplanen.

Uploadtests verwenden ausschließlich temporäre Verzeichnisse: python -m unittest discover -s tests -q.

Zentrales Logging

Webanwendung und Hilfsprogramme verwenden dieselbe idempotente Logging-Konfiguration. Entwicklung: python server.py; Dienstbetrieb: python server.py --no-reload. webservice/webservice.bat verwendet diesen Einstieg ohne zusätzliche Dateiumleitung. Nach Änderungen an Konfiguration oder Dienstskript den Dienst neu starten.

LOG_LEVEL=INFO
LOG_DIR=logs
LOG_TO_FILE=true
LOG_TO_CONSOLE=true
LOG_RETENTION_DAYS=30
LOG_SQL_STATEMENT=true

Relative Logverzeichnisse beziehen sich auf den Projektstamm. application.log enthält je Ereignis eine JSON-Zeile; die Konsole zeigt dieselben Ereignisse lesbar an. LOG_LEVEL akzeptiert DEBUG, INFO, WARNING, ERROR und CRITICAL. Beide Ausgaben lassen sich unabhängig abschalten. Die Zeitstempel enthalten Millisekunden und den Europe/Berlin-Offset. Die tägliche Rotation erfolgt dagegen um Mitternacht UTC. Eigene Archive heißen application.log.YYYY-MM-DD; Archive älter als die konfigurierte Aufbewahrungsdauer werden beim Start und bei Rotation entfernt. Frühere Dienstlogs bleiben erhalten.

Alle Prozesse müssen dasselbe Verzeichnis und dieselben Rotationseinstellungen verwenden. concurrent-log-handler koordiniert Schreiben und Rotation über Dateisperren, auch unter Windows. Das Dienstkonto benötigt Auflisten, Anlegen, Lesen, Schreiben, Umbenennen und Löschen für Logdateien, Archive und Sperrdateien im Logverzeichnis. Fehlende Schreibrechte, Rotations- oder Schreibfehler erzeugen eine datenarme Konsolenmeldung; bei Dateiausfall bleibt die Konsole als Fallback verfügbar. Deshalb auch die Dienstkonsole erfassbar halten. Logs nur den erforderlichen Betriebskonten zugänglich machen.

HTTP-Abschlüsse enthalten event=http_completed, eine eigene event_id, request_id, Benutzerkennung (soweit angemeldet), Methode, Pfad, Status und Laufzeit in Millisekunden. Die Antwort liefert dieselbe Request-ID als X-Request-ID. Zur Fehlersuche beispielsweise:

Select-String -LiteralPath .\logs\application.log -Pattern 'REQUEST-ID-AUS-DER-ANTWORT'

4xx werden als WARNING, 5xx als ERROR und andere Anfragen als INFO erfasst. Erfolgreiche Abrufe unter /static/ und /health erscheinen nur mit DEBUG. Loginanforderungen haben zusätzlich event=auth_login_required, auch bei HTMX-Antworten mit HTTP 200. Uvicorns separates Zugriffslog ist abgeschaltet. Unerwartete Exceptions werden einmal technisch erfasst; der HTTP-Abschluss bleibt ein eigenes, über die Request-ID zugeordnetes Ereignis. Fehler nach Beginn einer Streamingantwort behalten den tatsächlich gesendeten Status. Fehler, die IIS oder ein vorgeschalteter Proxy vor Python erzeugt, stehen weiterhin in den jeweiligen Serverlogs.

Datenbankfehler haben event=database_error mit Operation, Abfrageherkunft, query_fingerprint, Exceptiontyp, verfügbaren technischen Fehlercodes und Stackframes (Dateiname, Funktion, Zeile). Templateabfragen tragen ihren SQL-Dateinamen als Herkunft. Für SQL Server werden zusätzlich db_code (nativer Fehlercode, etwa 207), sqlstate und db_message (bereinigte Serverbeschreibung) ausgegeben. db_diagnostics enthält auch weitere ODBC-Meldungen desselben Fehlers mit jeweils Code, SQLSTATE und Beschreibung. Diese Angaben bleiben bei LOG_SQL_STATEMENT=false verfügbar. Zitierte Inhalte, zurückgemeldete Parameterwerte und Wertetupel werden in den Beschreibungen maskiert; es wird nicht die um SQL und Parameter ergänzte SQLAlchemy-Exception ausgegeben. Ausnahme: Bei SQL-Server-Fehler 207 („Ungültiger Spaltenname“ / „Invalid column name“) bleibt der Spaltenname in der Standardmeldung sichtbar, auch bei abgeschaltetem SQL-Text. SQL-Parameter, lokale Variablen und ungeprüfte Exceptiontexte werden nicht ausgegeben. SQL-Kommentare werden entfernt und Zeichenketten- sowie Zahlenliterale maskiert; der SQL-Text wird auf 8192 Zeichen begrenzt. Mit LOG_SQL_STATEMENT=false entfällt auch diese bereinigte Anweisung; Fingerabdruck und Herkunft bleiben erhalten. Abgefangene Datenbankfehler werden ebenfalls erfasst, weitere Logger erzeugen für dieselbe Exception keinen zweiten technischen Datensatz. Ein zusätzlicher Rollbackfehler bleibt sichtbar. Neue Logaufrufe dürfen keine Passwörter, Tokens, Header, Queryparameter, Formularinhalte, Mailbetreffzeilen oder Datei-/PDF-Inhalte enthalten. Binärdaten nur über ihre Größe erfassen.

Hilfsskripte mit Paketimporten starten: python -m app.imap, python -m app.cleanup_comments, python -m app.docuware_search beziehungsweise python filter_export.py. Diese Programme behalten ihre fachlichen Aktionen bei; ein Import allein führt sie nicht aus. Nicht zu Logging-Testzwecken produktiv starten. Loggingtests nutzen ausschließlich temporäre Verzeichnisse und isolierte SQLite-Engines: python -m unittest tests.test_logging -q. Die vollständige Prüfung erfolgt mit python -m unittest discover -s tests -q.