Ein Scanner löst das Papierproblem nur zur Hälfte. Danach liegt die Rechnung nicht mehr auf dem Schreibtisch, sondern als scan_0042.pdf in einem Verzeichnis. Man kann sie öffnen, aber noch lange nicht zuverlässig wiederfinden. Bei E-Mails ist es ähnlich: Der Anhang ist irgendwo vorhanden, der Zusammenhang steckt im Postfach, und ob beides wirklich gesichert ist, bleibt eine andere Frage.
Paperless-ngx soll in meinem Lab genau diese Lücke schließen: Dokumente aufnehmen, durchsuchbar machen und mit brauchbaren Metadaten versehen. Die interessante Arbeit begann allerdings erst nach dem ersten erfolgreichen Upload. Wie landet ein Scan vollständig im Archiv? Was darf ein Sprachmodell entscheiden? Und wie stelle ich Dateien und Datenbank so wieder her, dass sie auch zusammenpassen?
Das Archiv ist eine Verarbeitungskette#
Ich betreibe Paperless als eigene Anwendung im Kubernetes-Cluster, nicht als lose Sammlung von Containern auf einem zusätzlichen NAS. Die Infrastruktur kommt über Flux aus Git; Anwendungszustand liegt auf Ceph und in PostgreSQL.
Die Bausteine haben bewusst getrennte Aufgaben:
| Baustein | Verantwortung |
|---|---|
| Paperless-ngx | Import, OCR, Suche, Dokumente und Metadaten |
| CloudNativePG | PostgreSQL für das Archiv; separate Datenbank für LiteLLM |
| Dragonfly | Redis-kompatible Task- und Koordinationsdienste |
| Tika und Gotenberg | Extraktion und Konvertierung zusätzlicher Dokumentformate |
| SFTPGo | kontrollierter Übergang vom Scanner ins Consume-Verzeichnis |
| LiteLLM | Modellzugang, virtuelle Schlüssel und Budgetkontrolle |
Paperless ist auf Version 3.1.2 samt Image-Digest festgelegt. Für OCR sind Deutsch und Englisch konfiguriert, für die Suche Deutsch. Zwei Task-Worker mit jeweils einem Thread begrenzen die parallele Verarbeitung. Das ist ein bewusst überschaubarer Aufbau, keine Behauptung unbegrenzten Durchsatzes.
Auch Hochverfügbarkeit sollte man hier nicht hineinlesen: Paperless und seine PostgreSQL-Instanz laufen jeweils als Singleton. Der Nutzen des Clusters liegt zunächst in deklarativem Betrieb, gemeinsamem Storage, Netzwerkregeln und Backups, nicht in einer wundersam ausfallsicheren Einzelanwendung.
Ein Volume, aber mehrere Arten von Zustand#
Ein 100-GiB-RWO-Volume enthält die Unterverzeichnisse data, media, consume und export. Die Deployment-Strategie ist Recreate: Bei einem Update soll nicht ein zweiter Paperless-Pod gleichzeitig dasselbe Dokumentenvolume bearbeiten.
Die Trennung innerhalb des Volumes ist praktisch, ersetzt aber keine Trennung der Verantwortlichkeiten:
- Dokumentdateien liegen auf dem PVC.
- Metadaten, Benutzer, Mailregeln und Workflows liegen in PostgreSQL.
- LiteLLM-Schlüssel und Abrechnungszustand liegen in einer eigenen Datenbank.
- Die gewünschte Infrastruktur liegt in Git.
Das ist der erste wichtige Unterschied zwischen „alle YAML-Dateien gesichert“ und „Anwendung wiederherstellbar“. Ein frischer Flux-Reconcile baut die Dienste wieder auf. Er rekonstruiert nicht automatisch die Regeln, die in der Paperless-Datenbank gepflegt wurden.
Der Scanner bekommt einen schmalen Eingang#
Für den Scanner habe ich keine allgemeine Dateifreigabe auf das Archiv gelegt. Er bekommt einen SFTP-Endpunkt, hinter dem ein SFTPGo-Sidecar im Paperless-Pod sitzt. Beide Container sehen dasselbe Consume-Verzeichnis; das RWO-Volume muss nicht für einen zweiten Pod geöffnet werden.
Der Sidecar läuft im Portable Mode und braucht dafür weder eine zusätzliche Administrationsoberfläche noch eine eigene Datenbank. Sein Konto darf auflisten, hochladen und vorhandene Upload-Dateien ersetzen. SSH-Kommandos sind nicht Teil dieses Zugangs. Akzeptiert werden die vorgesehenen Scanformate wie PDF, JPEG, PNG und TIFF.
Der entscheidende Schalter ist der atomare Upload. SFTPGo schreibt zunächst eine verborgene temporäre Datei und benennt sie erst nach erfolgreichem Transfer um. Paperless soll keinen halben Scan verarbeiten, nur weil es schneller auf das Dateisystem schaut als der Scanner überträgt.
1Upload beginnt → temporäre Datei → Transfer vollständig → Umbenennen → Consumer
Das ist keine verteilte Transaktion über das gesamte Archiv. Es ist eine klare Übergabegrenze an genau der Stelle, an der sonst ein schwer reproduzierbares Timing-Problem entsteht.
Der externe SFTP-Zugang läuft über eine LAN-LoadBalancer-Adresse und ist auf die Scanneradresse eingeschränkt, zusätzlich durch die NetworkPolicy. Pod-Verkehr innerhalb des Paperless-Namespace bleibt durch die gemeinsame Policy erlaubt. Für ältere Scanner-Firmware sind einige ältere SSH-Algorithmen zugelassen. Das ist ein bewusster Kompatibilitätskompromiss an einem eng begrenzten Eingang, kein Muster für einen öffentlich erreichbaren SSH-Dienst.
Ein Scanauftrag entspricht einem Dokument. Ein Stapel aus Rechnung, Vertrag und Brief wird nicht dadurch zu drei Dokumenten, dass später ein großes Sprachmodell darüber nachdenkt. Entweder werden die Vorlagen getrennt gescannt oder eine ausdrücklich konfigurierte mechanische Trennung verwendet. Semantische Klassifikation ersetzt keine zuverlässige Eingangsgrenze.
E-Mail-Import: Auswahl vor Automatik#
Ein Dokumentenarchiv sollte nicht ungefragt das gesamte Postfach verschlucken. Der öffentlich dokumentierte Importablauf beginnt deshalb mit einer bewussten Auswahl von Nachrichten, nicht mit einer Regel über die komplette Inbox.
Das Modell verwendet drei Ordner. Mit neutralen Beispielnamen sieht es so aus:
1Archiv/Import
2 │ vollständige Nachricht als EML aufnehmen
3 ▼
4Archiv/Anhänge
5 │ unterstützte, nicht eingebettete Anhänge separat aufnehmen
6 ▼
7Archiv/Verarbeitet
8 └─ aufbewahren, abgleichen, erst später manuell löschen
Warum nicht einfach „Mail und Anhänge importieren“ in einem Schritt? Bei der eingesetzten Paperless-Version laufen Teile der Verarbeitung asynchron. Wird die Nachricht schon verschoben, während ein zweiter Zweig noch arbeitet, entsteht ein unnötiges Rennen. Zwei getrennte Regeln machen den Fortschritt an der Ordnerposition erkennbar.
Der letzte Ordner ist dabei kein automatischer Papierkorb. Eine erfolgreich abgeschlossene Importaktion beweist noch nicht, dass jede Nachricht und jeder Anhang im gewünschten Zustand wiederherstellbar ist. Vor dem Löschen gehören Abgleich, Integritätsprüfung und ein getesteter Rückweg dazu.
Ein kleiner, aber wichtiger Stolperstein ist der IMAP-Ordnertrenner. Was ein Mailclient als Archiv/Import anzeigt, kann auf dem Server beispielsweise Archiv.Import heißen. Eine hübsche Darstellung im Client ist keine verlässliche API-Bezeichnung.
Ein identischer Anhang ist nicht dasselbe wie ein ähnlicher Scan#
Die konfigurierte Duplikatbehandlung erkennt byteidentische Originale über ihre Prüfsumme. Derselbe PDF-Anhang aus einer erneut eingelesenen Mail kann dadurch als bereits vorhanden erkannt werden, ohne die Importkette dauerhaft aufzuhalten.
Ein neuer Scan desselben Papierblatts hat dagegen fast sicher andere Bytes. OCR-Ähnlichkeit kann Kandidaten liefern, ist aber keine verlässliche Löschentscheidung. Gerade bei Rechnungen können zwei fast identische Dokumente unterschiedliche Geschäftsvorgänge sein.
Für mich folgt daraus eine einfache Reihenfolge: klein anfangen, Treffer prüfen, Bestand verstehen. Nicht erst ein ganzes Postfach importieren und danach hoffen, dass ein unscharfer Vergleich schon weiß, was weg darf.
KI ist ein Klassifikator, kein Archivverwalter#
Die KI-Anbindung nutzt Paperless’ integrierte Metadatenvorschläge. paperless-ai ist dabei ein interner Modellalias, kein zusätzlich installierter Dienst gleichen Namens.
Der tatsächliche Pfad lautet:
1Paperless
2 → OpenAI-kompatible interne API von LiteLLM
3 → native Ollama-Chat-API
4 → mistral-large-3:675b-cloud
„OpenAI-kompatibel“ bezeichnet hier das Protokoll zwischen Anwendung und Gateway, nicht den verwendeten Cloudanbieter. Das Modell läuft bei Ollama Cloud, nicht lokal auf meinen Cluster-Nodes.
Das Gateway ist aus zwei Gründen nützlich. Erstens erhält Paperless nur einen begrenzten virtuellen Schlüssel, nicht den Provider-Schlüssel. Zweitens lassen sich Modellroute, Parallelität und Budget an einer Stelle kontrollieren, ohne sie in jeder Anwendung neu zu implementieren.
Strukturierte Ausgabe ist eine Schnittstelle#
Ein brauchbarer Klassifikator soll nicht einen schönen Absatz über die Rechnung verfassen. Er soll Daten in der erwarteten Struktur liefern. Der konfigurierte Pfad fordert deshalb den nativen DocumentClassifierSchema-Tool-Call.
Die Wahl der Providerroute ist dabei nicht kosmetisch: Tool-Calls müssen vom Modell bis zum Paperless-Parser erhalten bleiben. Eine nominell kompatible API ist noch kein Nachweis, dass alle strukturierten Ausgaben identisch funktionieren.
Ein versionsgebundener Kompatibilitätspatch fordert deutsche Titel, Tags und Dokumenttypen bereits im ersten Aufruf an und unterdrückt einen zweiten Lokalisierungsschritt. Eigennamen sollen unverändert bleiben. Das reduziert eine zusätzliche Fehlerstelle, ist aber auch eine bewusst eingegangene Wartungslast.
Der Patch prüft seine erwarteten Quelltextstellen exakt. Passt ein zukünftiges Paperless-Image nicht mehr dazu, schlägt der Init-Schritt fehl. Das ist unangenehmer als ein scheinbar erfolgreiches Update, aber besser als eine still falsch gepatchte Klassifikation.
Die Konsequenz für Updates: Image und Kompatibilitätspfad zusammen testen. Einen Digest auszutauschen ist hier nicht der vollständige Upgrade-Test.
Die überraschend wichtige Reihenfolge: erst Eigentümer, dann Vorschläge#
Der öffentlich dokumentierte Klassifikationsablauf trennt deterministische Zuweisung von asynchroner KI-Arbeit:
- Zu Beginn der Verarbeitung werden Eigentümer und ein fester Ablagepfad zugewiesen.
- Nach dem Anlegen und Parsen des Dokuments wird die KI-Klassifikation angestoßen.
- Das Ergebnis darf ausgewählte Metadaten ergänzen beziehungsweise ersetzen.
Der Eigentümer ist keine dekorative Spalte. Paperless gleicht Vorschläge mit der Taxonomie ab, die für den Dokumenteigentümer sichtbar ist. Ein Scan ohne Eigentümer kann daher vorhandene, benutzereigene Tags oder Dokumenttypen nicht so zuordnen wie erwartet. Die richtige KI-Antwort allein reicht nicht: Der Anwendungskontext muss vorher stimmen.
Der Ablagepfad bleibt absichtlich eine feste Workflow-Entscheidung. Das Modell soll nicht bestimmen, in welchen organisatorischen Bereich ein Dokument gehört. Und ein Verzeichnisname ist ohnehin keine Zugriffskontrolle; die gehört in Eigentümer, Gruppen und Dokumentberechtigungen.
Für die eigentlichen Vorschläge beschreibt das Runbook folgende Auswahl:
1Felder: Titel, Tags, Dokumenttyp, Dokumentdatum
2Neue Taxonomie: nicht automatisch erzeugen
3Vorhandene Werte: für diese Felder überschreiben erlauben
4Ablagepfad: nicht vom Modell wählen lassen
5Benutzerdef. Felder: nicht durch KI-Vorschläge befüllen
Das Überschreiben klingt zunächst großzügig, ist hier aber nötig: Ein frisch eingelesener Scan besitzt bereits einen Dateinamen als Titel und ein Datum. „Nur leere Felder füllen“ würde ausgerechnet diese Werte oft unverändert lassen.
Ein synthetisches Beispiel: Aus scan_0042.pdf kann „Rechnung Beispiel GmbH – September 2026“ werden, mit dem bereits vorhandenen Dokumenttyp Eingangsrechnung. Rechnungsnummer, Zahlungsstatus oder ein prüfpflichtiger Geldbetrag sind damit noch lange nicht korrekt extrahiert. Sie bleiben ein eigener, kontrollierter Arbeitsschritt.
Die KI-Aktion ist vom eigentlichen Import entkoppelt. Schlägt sie fehl, soll das Dokument trotzdem aufgenommen werden und für die manuelle Nachbearbeitung vorhanden bleiben. Im dokumentierten Ablauf werden Timeouts begrenzt wiederholt; ein Budgetblock wird nicht durch endlose Retries „repariert“.
Kostenkontrolle braucht einen verlässlichen Zähler#
LiteLLM begrenzt den virtuellen Schlüssel auf den vorgesehenen Modellalias. Dazu kommen eine parallele Anfrage, zehn Requests pro Minute, 50.000 Tokens pro Minute und maximal 2.048 Ausgabetokens pro Antwort.
Für die Abrechnung sind Tages- und Monatsfenster konfiguriert: 15 beziehungsweise 300 in LiteLLMs USD-Recheneinheiten. Diese Werte werden mit hinterlegten Tokenpreisen verrechnet. Sie sind keine Zusicherung über die tatsächliche Rechnung oder Vertragslogik des Providers.
Wichtiger als die Zahlen ist die Fehlersemantik: Budgetreservierungen hängen an PostgreSQL. Ist der maßgebliche Abrechnungszustand nicht verfügbar, soll das Gateway Anfragen ablehnen, statt sie ungezählt durchzulassen.
Ein kleiner Reconciler hält Schlüssel und Limits aktuell. Er schreibt die Budgetfenster jedoch nicht bei jedem Lauf erneut: Die eingesetzte LiteLLM-Logik kann dadurch den Reset-Zeitpunkt verschieben. Eine vermeintlich idempotente Aktualisierung hätte dann die Grenze verändert, die sie eigentlich durchsetzen soll.
Auch die Kontextgrößen gehören getrennt betrachtet. Paperless ist auf 8.192 Tokens konfiguriert; die Gateway-Metadaten beschreiben ein größeres Modellfenster. Das zweite macht das erste nicht automatisch größer. Ein langer Vertrag wird nicht allein durch eine große Zahl in der Providerkonfiguration vollständig ausgewertet.
Datenschutz ist ein Datenfluss, kein Standortetikett#
Das Archiv läuft im eigenen Cluster. Die Cloudklassifikation verarbeitet trotzdem Dokumentinhalt außerhalb davon. Beides ist gleichzeitig wahr.
Deshalb gehört vor automatische KI-Verarbeitung eine bewusste Entscheidung darüber, welche Dokumentklassen diesen Weg nehmen dürfen. Besonders sensible Inhalte sind nicht allein deshalb für ein Cloudmodell geeignet, weil der Upload in eine selbst betriebene Anwendung erfolgt.
Die Netzwerkregeln bilden die Trennung technisch ab: Paperless nutzt das interne Gateway; LiteLLM hat den expliziten Zugang zum Modellanbieter. Tika und Gotenberg erhalten keinen ausgehenden Netzwerkzugang. Ein Konverter soll nicht nebenbei Tracking-Pixel oder externe Office-Ressourcen nachladen.
Prompt-Logging ist reduziert, und Prompts sollen nicht in den Spend-Logs landen. Das ersetzt keine Prüfung der Verarbeitungs- und Speicherbedingungen beim Cloudanbieter.
RAG und Dokumentchat sind nicht aktiviert. Das Embedding-Backend ist ungesetzt; es gibt keinen still im Hintergrund wachsenden Vektorindex. Ich möchte zunächst den Dokumentenfluss und die Metadaten beherrschen, bevor eine weitere abgeleitete Datenhaltung hinzukommt.
Zugang: privates Netz und eigene Anmeldung#
Die Weboberfläche ist über einen nativen tailnet-operator-Ingress erreichbar. Der Agent terminiert HTTPS und leitet an Paperless weiter. Größere Uploads und längere Verarbeitungspfade bekommen explizite Request-Budgets statt eines zufällig passenden Standardtimeouts.
Die Anwendung authentifiziert ihre Benutzer selbst über Pocket ID mit OIDC und PKCE. Lokale und soziale Selbstregistrierung sind deaktiviert; ein lokaler Wiederherstellungslogin bleibt erhalten.
Das sind zwei unterschiedliche Schranken: Das Tailnet bestimmt, wer die Anwendung überhaupt erreichen darf. Paperless bestimmt, wer angemeldet ist und welche Dokumente sichtbar sind. Eine private Netzwerkadresse ersetzt diese zweite Ebene nicht.
Backup: Dateien und Datenbank müssen sich wieder treffen#
Das Dokumentenvolume wird täglich über VolSync und restic gesichert, mit getrennten Zielen bei BorgBase und Cloudflare R2. PostgreSQL hat zusätzlich lokale Snapshots, Barman-Basisbackups und WAL-Archivierung nach Garage. Der gemeinsame Archivpfad wird verschlüsselt nach R2 kopiert.
Garage ist dabei ein lokaler Zwischen- und Wiederherstellungsspeicher. Es liegt im selben Cluster wie das Archiv und ist allein keine unabhängige Katastrophensicherung.
Die anspruchsvolle Stelle ist nicht der Upload, sondern der gemeinsame Wiederherstellungszeitpunkt. PVC-Snapshots und Datenbankbackups laufen getrennt; sie bilden keine gemeinsame Transaktion.
1Anwendungen stoppen
2 → passenden PVC-Snapshot wählen
3 → PostgreSQL auf einen dazu passenden Zeitpunkt wiederherstellen
4 → Dokumentenvolume wiederherstellen
5 → Anwendungen starten
6 → Konsistenz und Dokumentzugriff prüfen
Das dokumentierte Restore-Modell wählt den Datenbankzeitpunkt nicht später als den gewählten PVC-Snapshot. Damit soll die Datenbank nicht bereits auf Dateien zeigen, die im wiederhergestellten Volume noch fehlen. Trotzdem bleiben Konsistenzprüfung und ein isolierter Probelauf notwendig; ein Zeitvergleich allein beweist keinen fehlerfreien Gesamtzustand.
Ein portabler document_exporter-Export kann diesen Rückweg ergänzen. Er ist im beschriebenen Aufbau aber kein automatisch laufender zusätzlicher Sicherungsjob. Und ich leite aus vorhandenen Backup-Manifesten keinen bereits bestandenen kompletten Disaster-Recovery-Test ab.
Was ich vor einem großen Import prüfen würde#
Nicht tausend Dokumente als ersten Integrationstest verwenden. Eine kleine, repräsentative Testmenge beantwortet die wichtigen Fragen schneller:
- Kommt ein mehrseitiger Scan erst nach vollständigem Upload im Consumer an?
- Bleiben EML und Anhänge im vorgesehenen Ablauf nachvollziehbar?
- Wird ein erneut gelieferter identischer Anhang als Duplikat erkannt?
- Stehen Eigentümer und Taxonomie fest, bevor die KI arbeitet?
- Bleibt ein Dokument bei Modellfehler oder Budgetblock manuell bearbeitbar?
- Funktionieren OIDC-Anmeldung, Vorschau und Originaldownload?
- Lassen sich Dateien und Datenbank isoliert in einem konsistenten Zustand wiederherstellen?
Das sind keine Nebensächlichkeiten um die eigentliche KI-Funktion herum. Es ist die eigentliche Integration.
Fazit#
Paperless macht aus Scans ein Archiv. Belastbar wird dieses Archiv aber durch die Grenzen dazwischen: vollständige Dateien statt halber Uploads, ausgewählte Mails statt einer ungeprüften Inbox, feste Zuständigkeiten statt freier KI-Ablage und zusammenpassende Backups statt zweier unabhängig grüner Jobs.
Die KI nimmt mir dabei einen Teil der Sortierarbeit ab. Sie bekommt weder die Entscheidung über meine Ablagestruktur noch das letzte Wort über fachliche Richtigkeit. Genau so ist sie nützlich: als begrenzter Arbeitsschritt in einem nachvollziehbaren System, nicht als neue Vertrauenswurzel.
Quellenstand: öffentliche Lab-Manifeste Anfang Oktober 2026, insbesondere applications/paperless/, plus der dortigen Git-Historie entnommene Betriebsabläufe aus docs/PAPERLESS.md vor der Dokumentationsbereinigung 26d3bf37. Das Lab-Repository
enthält Konfiguration und Historie; persönliche Dokumente, Konten und konkrete Netzwerkadressen sind hier absichtlich nicht abgebildet.
