|
|
4 gün önce | |
|---|---|---|
| .vscode | 1 ay önce | |
| app | 4 gün önce | |
| data | 6 gün önce | |
| migrations | 1 ay önce | |
| scripts | 4 gün önce | |
| static | 4 gün önce | |
| templates | 4 gün önce | |
| tests | 4 gün önce | |
| webservice | 1 hafta önce | |
| .env.example | 6 gün önce | |
| .gitignore | 4 gün önce | |
| .python-version | 9 ay önce | |
| README.md | 4 gün önce | |
| filter_export.py | 1 hafta önce | |
| pyproject.toml | 1 hafta önce | |
| server.py | 1 hafta önce | |
| specs.md | 9 ay önce | |
| tox.ini | 9 ay önce | |
| uv.lock | 1 hafta önce |
Das ultimative Tool für:
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
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.
Öffne http://127.0.0.1:8000 im Browser.
Alle Browser-Bibliotheken, Schriftdateien und CSS-Abhängigkeiten liegen unter
static/assets im Repository. Auch das erst beim Öffnen des Dashboards geladene
Chart.js wird lokal ausgeliefert. Login und Anwendung benötigen keine Verbindung
zu CDNs oder Google Fonts und funktionieren auch mit leerem Browser-Cache.
Der Anwendungsserver sowie die konfigurierten Datenbank-, LDAP- und
Dokumentendienste müssen weiterhin erreichbar sein; ein Betrieb ohne Server ist
damit nicht verbunden.
Quellen und SHA-256-Prüfsummen der eingebundenen Drittanbieterdateien stehen in
static/assets/vendor/manifest.json. Lizenzdateien liegen bei den jeweiligen
Assets; für CoreUI PRO gilt weiterhin dessen kommerzielle Lizenz.
Nur zur bewussten Aktualisierung der lokalen Dateien ist Internetzugang nötig:
.venv\Scripts\python.exe scripts/vendor_assets.py
Das Skript enthält die Paketversionen, lädt CSS-Abhängigkeiten rekursiv herunter
und schreibt deren Verweise auf lokale Dateien um. Nach einer Unterbrechung kann
der Download mit --resume fortgesetzt werden. Anschließend alle aktualisierten
Assets einschließlich Manifest zusammen übernehmen. Das ungenutzte CommonJS-Modul
der CoreUI-Icons wird nicht als Browser-Skript eingebunden; die Icons kommen aus
dem lokalen Stylesheet und dessen Schriftdateien. Nicht mitgelieferte und in der
Anwendung ungenutzte Hintergrundbilder des alten Login-Templates werden nicht
mehr referenziert.
Die Offline-Ressourcenprüfung läuft ohne externe Dienste:
.venv\Scripts\python.exe -m unittest tests.test_offline_assets
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.
migrations/001_authentication.sql auf der Anwendungsdatenbank ausführen..env.example nach .env kopieren und alle Platzhalter ersetzen.JWT_SECRET mit mindestens 32 Byte konfigurieren.TRUSTED_PROXY_IPS eintragen und den FastAPI-Port nicht extern freigeben.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
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.
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.
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. Die Wiedervorlagestapelung übernimmt Schlüssel, Reihenfolge und
Bezeichnung direkt aus Forderungen_Liste.Wiedervorlage_Staffel_Nr und
Wiedervorlage_Staffel_Text. Die Einstufung wird von der Datenquelle geliefert:
„Überfällig“, heute bis in 3 Tagen, in 4 bis 20 Tagen und ab 21 Tagen „zurückgestellt“.
Das Dashboard berechnet diese Einstufung nicht zusätzlich aus Datumsfeldern.
Fehlt die Staffelnummer, erscheint der Beleg unter „Ohne WV-Staffel“.
Segmentlinks übernehmen die Staffelnummer in den bestehenden Listenfilter WVStaffel;
Gruppenlinks öffnen alle Staffeln der Gruppe. Dadurch stimmen Anzahl und Betrag im
angeklickten Segment mit der gefilterten Liste überein.
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; dort wird dafür RechnungGutschrift=Rechnung gesetzt.
Dashboardlinks verwenden die normalen Listenfilter: Standort setzt Mandant und Filiale,
Altersstaffel setzt Staffel, Verursacher setzt den Namen in Verursacher. Gleichnamige
Verursacher werden deshalb gemeinsam dargestellt. Ein Abteilungssegment ergänzt Abteilung.
Alle übernommenen Werte sind in den vorhandenen Filterfeldern sichtbar, änderbar und
entfernbar. Es wird kein zusätzlicher Dashboardfilter erzeugt. Gruppen ohne Wert verwenden
die reguläre Auswahl „Ohne Wert“ (__empty__), die NULL und leere Zeichenketten umfasst.
Textfelder behalten ihre Teiltextsuche, Auswahlfelder vergleichen die Schlüssel exakt.
Alte Listenlinks mit dashboard_segment werden in normale Listenparameter umgewandelt
und auf diese URL weitergeleitet. Es gibt keinen versteckten Dashboardfilter und keine
separate Dashboardfilter-Anzeige mehr. Bereits gesetzte normale Filter haben Vorrang.
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.
Auswahl- und Textfelder unterstützen mehrere Werte in suchbaren Dropdowns mit Checkboxen. Textfelder erlauben zusätzlich freie Suchbegriffe, die mit Enter übernommen werden. Änderungen werden beim Schließen des Dropdowns angewendet; einzelne Werte können direkt entfernt werden. Während die Liste aktualisiert wird, erscheinen ein Wartesymbol und „Filter werden angewendet …“; sämtliche Filtereingaben sind bis zum Abschluss gesperrt. Auch bei einem abgebrochenen oder fehlgeschlagenen Aufruf wird die Sperre aufgehoben. Innerhalb eines Feldes gilt ODER, zwischen Feldern UND. Datumsgrenzen bleiben einzelne Werte. Vorschläge beachten alle anderen Filter, aber nicht die eigene Feldauswahl. Sie stammen ausschließlich aus berechtigten Forderungen.
Die GET-Parameternamen bleiben unverändert, beispielsweise Filiale=10,20. Jeder Einzelwert
wird URL-kodiert, bevor die Werte mit Kommas verbunden und als GET-Parameter kodiert werden.
Die Trennkommas bleiben dabei sichtbar (Mandant=1,2), auch beim Filtern und Nachladen.
Ein Komma im Wert erscheint dadurch als %252C in der fertigen URL, beispielsweise
Kunde=M%25C3%25BCller%252C%2520GmbH,Meier. Nach dem normalen GET-Dekodieren zuerst
an Kommas trennen und danach jeden Einzelwert genau einmal dekodieren. Einfache bestehende
Einzelwert-Links bleiben gültig. Leere Einträge und doppelte Werte werden entfernt.
GET /app/forderungen/liste/vorschlaege nimmt die Listenfilter sowie field und search
entgegen. Die authentifizierte Antwort enthält höchstens 50 eindeutige, sortierte
items mit value und label sowie has_more. Bei weiteren Treffern muss die Suche
eingegrenzt werden. Ungültige Felder oder Dashboardfilter ergeben HTTP 400.
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.
„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.
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.
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.
Eine optionale mehrzeilige „Begründung“ wird nach einem Doppelpunkt an diesen Kommentar
angehängt; Leerzeichen am Anfang und Ende werden entfernt. Bei Validierungs- oder
Speicherfehlern bleiben Datum und Begründung im Dialog erhalten.
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.
Chat und Wiedervorlage speichern Kommentare über dieselbe Funktion. Hat der Autor in
dbo.Benutzer_Rolle mindestens eine Zuordnung mit Rolle_ID = 'FIBU', erhält der neue
Kommentar Aktuell_Fibu = 1, andernfalls Aktuell_Abteilung = 1; das jeweils andere
Flag des neuen Kommentars ist 0. Bei bisherigen Kommentaren derselben Kombination
aus Client_DB und Beleg_Nr wird nur das entsprechende Flag auf 0 gesetzt.
Flags, Kommentar und gegebenenfalls Datum werden gemeinsam gespeichert oder
zurückgerollt. Eine SQL-Server-Sperre auf dem Forderungskopf serialisiert beide
Speicherwege. Reine Datei-Uploads verändern die Flags nicht. Die beiden Flagspalten
und Benutzer_Rolle.Rolle_ID müssen bereits im Datenbankschema vorhanden sein.
Ü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.
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.
Der Belegnummer-Button öffnet eine Liste aus DocuWare und lokaler Ablage.
Die Detailseite bietet zusätzlich „Offene Belege“, „Kunde“ und „Fahrzeug“.
Kunde und Fahrzeug durchsuchen DocuWare direkt; beim Fahrzeug wird die VIN aus
dbo.Fahrzeuge verwendet. Lokale Dateien werden aus den passenden aktuellen und
historischen Belegen ergänzt, beim Fahrzeug auch über Kundenwechsel hinweg.
Die Zuordnung bleibt im Mandanten der geöffneten Forderung.
Fehlende Metadaten bleiben leer. Lokale PDFs öffnen als Vorschau, andere Dateien
werden heruntergeladen. DocuWare-Ausfälle blenden lokale Dateien nicht aus.
In .env explizit einschalten:
DOCUWARE_MODE=mock
DOCUWARE_MOCK_PATH=data/docuware-sample
Die mitgelieferten Testmetadaten verwenden Mandant 1, Belege R1/R2, Kunde
D1 und VIN VIN1/VIN2. Sie verwenden die bisherige Beispiel-PDF ausschließlich
als bewusst aktivierte Mockdatei. Für andere Entwicklungsbelege können die
Metadaten in einer Kopie angepasst werden. Eine nicht vorhandene Belegnummer
simuliert eine leere Suche; "unavailable": true auf Manifestebene simuliert einen
Ausfall. Fehlende file-Einträge simulieren einen Fehler beim Dokumentabruf.
Der Livemodus greift niemals automatisch auf diese Beispiele zurück.
Auf einem System mit DocuWare-Zugang und bestehender DW_*-Konfiguration:
.venv/Scripts/python.exe -m app.docuware_export --client-db 1 --document-no R1 --document-no R2 --output data/docuware-exports/testlauf
# Optional: --customer-no D1 oder --vehicle-no VIN1 (zusätzliche Suchläufe)
Den gesamten Ausgabeordner in die Entwicklungsumgebung kopieren und
DOCUWARE_MOCK_PATH darauf setzen. Ein bestehendes Manifest wird nicht überschrieben.
manifest.json enthält Formatversion 1, Metadaten, relative PDF-Pfade und einen
Fehlerbericht. Der Exitcode ist bei Teilfehlern 1. Dateinamen werden aus Archiv und
Dokument-ID abgeleitet. Zugangsdaten und Sitzungstokens werden nicht exportiert.
Produktivexporte unter data/docuware-exports/ sind von Git ausgeschlossen.
„Weiterleiten“ erzeugt eine .eml-Datei mit genau einem Anhang und X-Unsent: 1.
Empfänger stammen aus der geöffneten Forderung; fehlende Adressen deaktivieren das
jeweilige Ziel. „An mich“ verwendet Benutzer_Rolle.Benutzer_Email für den angemeldeten
Benutzer, ersatzweise dessen E-Mail-Adresse aus den Anmeldedaten. „Verursacher“ verwendet
Forderungen_Liste.Verursacher_Email für Mandant und Belegnummer der geöffneten Forderung;
fehlt eine gültige Adresse, bleibt die AD-Abfrage des aktuellen Verursachers als Rückfall.
Die Anwendung versendet keine E-Mails. Die Bearbeitbarkeit des Entwurfs muss im eingesetzten
Mailprogramm geprüft werden; sie hängt vom Client und dessen Dateizuordnung ab.
Vor Produktivfreigabe sind außerdem Suchfelder und PDF-Ausgabe am echten Archiv
zu prüfen. DW_TIMEOUT begrenzt die einzelnen DocuWare-Anfragen.