Files
pdf-ocr-hotfolder/config.example.toml
T
techadmin cd803a3dfe feat: stille Datenverlust-Pfade geschlossen, gemeinsame Shell-Lib (v0.7.0)
Vor dem Rollout durchgesehen und die verbliebenen Stellen geschlossen, an
denen etwas schiefgehen konnte, ohne dass es irgendwo sichtbar wurde.

Datenverlust:
- veraPDF: das in [verapdf].binary konfigurierte Programm wird im Preflight
  geprueft. Bisher galt bei falschem Pfad JEDE Datei als "nicht konform" —
  Ergebnis nach error/, Original geloescht (Default delete). run_verapdf()
  trennt jetzt ausserdem ein echtes FAIL-Urteil von einer Stoerung
  (VeraPdfUnavailable: nicht startbar, abgestuerzt, kein PASS/FAIL in der
  Ausgabe). Bei Stoerung wandern Original UND Ergebnis nach error/, das
  Original wird nicht entsorgt.
- Gleichnamige Dateien wurden in outgoing/, error/ und beim Ordner-Upload
  mit abweichendem target kommentarlos ueberschrieben. Jetzt Zeitstempel
  daneben, mit Warnung; ProcessResult.output traegt den echten Pfad.

Robustheit:
- Kaputtes oder nicht lesbares TOML beim Start: Exit 2 statt Traceback.
- RestartPreventExitStatus=2 in der Unit — Exit 2 (Config/Preflight) laeuft
  nicht mehr endlos neu, die Instanz bleibt sichtbar failed stehen.
- Toter watchdog-Observer wird erkannt: Exit 3, systemd setzt den Watch neu
  auf. Vorher blieb die Unit "active" und verarbeitete nichts mehr.
- Relative Pfade in [paths]/archive_dir/target sind ein Config-Fehler statt
  still unter /opt zu landen.
- Fehler beim Archivieren entwertet den Durchlauf nicht mehr: Upload und
  Mail laufen, Sichtbarkeit ueber log.error + "OK mit Warnung"-Mail.
- Nicht-PDFs in incoming/ werden beim Start-Scan gesammelt gemeldet.
- Logging explizit nach stdout (die Doku versprach das schon).

Struktur:
- Neue lib/common.sh, von install.sh und update.sh gesourct. Die doppelte
  venv_is_healthy() gibt es nur noch einmal, in der gruendlichen Fassung —
  die schlanke in install.sh haette eine nach einem Distro-Sprung kaputte
  venv als gesund durchgewunken (nachgewiesen).
- install.sh warnt in Containern, wenn systemd-journald nicht laeuft.

Doku: Dateisystem-Festlegung (ext4/xfs/zfs, kein CIFS/NFS wegen inotify),
Debian 13 in LXC auf Proxmox scheitert an journald (243/CREDENTIALS,
AppArmor blockiert sd-mkdcreds) inkl. Abhilfe, echte Speicher-Messwerte,
Exit-Code-Tabelle.

254 Tests gruen (vorher 152).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 00:59:17 +02:00

129 lines
5.0 KiB
TOML

# PDF OCR Hotfolder — Konfiguration
# Vorlage — install.sh erzeugt daraus pro Instanz /etc/pdf-ocr-hotfolder/<instanz>.toml
[paths]
# ACHTUNG: Alle Pfade MUESSEN absolut sein. Ein relativer Pfad wuerde gegen
# das Arbeitsverzeichnis des Dienstes aufgeloest (WorkingDirectory der
# systemd-Unit), nicht gegen das Verzeichnis dieser Datei — der Scanner
# schriebe dann woanders hin als der Dienst schaut. Der Dienst startet
# deshalb mit einem relativen Pfad gar nicht erst.
# Eingangsverzeichnis: hier landen gescannte PDFs
incoming = "/var/lib/pdf-ocr-hotfolder/incoming"
# Ausgangsverzeichnis: fertige durchsuchbare PDFs
outgoing = "/var/lib/pdf-ocr-hotfolder/outgoing"
# Arbeitsverzeichnis (während Verarbeitung)
working = "/var/lib/pdf-ocr-hotfolder/working"
# Fehlerverzeichnis: PDFs, die nicht verarbeitet werden konnten
error = "/var/lib/pdf-ocr-hotfolder/error"
[ocr]
# Tesseract-Sprachen (z.B. "deu", "deu+eng")
languages = "deu+eng"
# Anzahl Threads pro PDF (ocrmypdf --jobs)
jobs = 4
# Bereits OCR-haltige Seiten überspringen statt neu zu OCRen
skip_text = true
# Auflösung für gerasterte Seiten
oversample = 300
# PDF/A-Konformitätsstufe ("1", "2", "3" oder leer für keinen PDF/A-Output)
# ACHTUNG: Ghostscript 10.0.0 bis 10.02.0 (Debian 12 default!) haben einen Bug;
# ocrmypdf lehnt damit die Kombination pdfa_level + skip_text=true komplett ab.
# Nur auf "1"/"2"/"3" setzen, wenn gs >= 10.02.1 installiert ist.
#
# pdfa_level = "" ist deshalb der Default — aber KEIN genereller Schutz gegen
# den Ghostscript-Bug: das gilt erst zusammen mit ocrmypdf >= 17. Bis
# ocrmypdf 16.x läuft dieselbe Prüfung auch ohne PDF/A, und dann scheitert mit
# skip_text = true jede einzelne Datei. Die Entwarnung hängt also an der
# ocrmypdf-Version, nicht an dieser Zeile; requirements.txt pinnt darum 17.x.
# Der Preflight prüft beides zusammen und lässt den Dienst gar nicht erst
# starten, wenn die Kombination nicht trägt.
pdfa_level = ""
# Schiefe Scans automatisch begradigen
deskew = true
# Hintergrund säubern
clean = false
# Maximale parallele PDFs (Hauptsystem hat selten mehr als 1-2 gleichzeitig)
max_workers = 2
# Max. Sekunden, die Tesseract pro SEITE laufen darf (0 = kein Limit).
# ocrmypdf kennt kein Gesamt-Timeout pro Dokument, nur dieses Seiten-Limit
# (ocrmypdf-Option --tesseract-timeout). Läuft eine Seite in den Timeout,
# wird sie ohne Textebene ins Ergebnis übernommen; die Verarbeitung der
# restlichen Seiten läuft weiter.
# 0 = wir geben kein Limit vor und überlassen es dem ocrmypdf-Default.
timeout = 300
[output]
# Wie soll die Ziel-Datei im outgoing/-Ordner benannt werden?
# "prefix" : name_tag wird vor den Dateinamen gestellt (OCR_scan.pdf)
# "suffix" : name_tag wird vor die Extension gestellt (scan_OCR.pdf)
# "none" : Dateiname bleibt wie das Original
name_mode = "prefix"
# Verbatim einzufügender String. Leerer String = kein Tag (wie mode="none").
# Beispiele: "OCR_", "[OCR]_", "_OCR", "_searchable"
name_tag = "OCR_"
# Was passiert mit dem Original, wenn OCR erfolgreich war?
# "delete" : Original wird gelöscht (alter Standard)
# "archive" : Original wird in archive_dir verschoben
original_on_success = "delete"
# Absoluter Pfad (Pflicht, relativ wird abgelehnt); nur relevant wenn
# original_on_success = "archive"
archive_dir = ""
[verapdf]
# PDF/A-Validierung (optional)
# ACHTUNG: Mit enabled = true muss "binary" auf ein vorhandenes, ausfuehrbares
# Programm zeigen. Der Preflight prueft das und laesst den Dienst sonst gar
# nicht erst starten (--check-config meldet Exit 2). Grund: ein nicht
# aufrufbares veraPDF wuerde jede einzelne PDF als ungueltig werten, das
# OCR-Ergebnis nach error/ schieben und das Original laut
# original_on_success entsorgen — bei "delete" also Scan fuer Scan die
# Vorlage vernichten, waehrend der Dienst als "laeuft" dasteht.
enabled = false
binary = "/opt/verapdf/verapdf"
flavour = "1b"
# Upload-Ziele — beliebig viele aktivierbar.
# Wenn alle deaktiviert sind, bleibt das fertige PDF einfach im outgoing-Ordner.
[upload.folder]
enabled = true
# Wenn leer, wird [paths].outgoing verwendet. Sonst: absoluter Pfad (Pflicht,
# relativ wird abgelehnt). Liegt im Ziel schon eine gleichnamige Datei, wird
# die neue mit Zeitstempel abgelegt statt die alte zu ueberschreiben.
target = ""
[upload.nextcloud]
enabled = false
url = "https://cloud.example.com"
username = "scanuser"
password = "app-password"
# Zielpfad relativ zum User-Root, z.B. "Scans/Inbox"
remote_path = "Scans/Inbox"
verify_ssl = true
[upload.sftp]
enabled = false
host = "sftp.example.com"
port = 22
username = "scanuser"
# Entweder Key-Datei oder Passwort
key_file = "/etc/pdf-ocr-hotfolder/sftp_key"
password = ""
remote_path = "/uploads"
[notify.email]
enabled = false
smtp_host = "smtp.example.com"
smtp_port = 587
smtp_user = "alerts@example.com"
smtp_password = "secret"
use_starttls = true
from_addr = "PDF OCR Hotfolder <alerts@example.com>"
to_addrs = ["admin@example.com"]
# Wann benachrichtigen: "always" | "errors" | "never"
on = "errors"
[logging]
# DEBUG | INFO | WARNING | ERROR
level = "INFO"