Files
archivmail/features/PROJ-35-ocr-anhang-volltext.md
T

5.4 KiB
Raw Blame History

PROJ-35: OCR & Anhang-Volltext-Indexierung

Status: Planned

Created: 2026-04-04 Last Updated: 2026-04-04

Dependencies

  • Requires: PROJ-5 (Speicherung & Indexierung) — Mailparser + Manticore-Index
  • Requires: PROJ-30 (Manticore Migration) — Volltext-Index als Basis

Motivation

PDF- und Bild-Anhänge (Rechnungen, Verträge, eingescannte Dokumente) sind bisher nicht durchsuchbar — nur der Dateiname wird indexiert. OCR macht den Inhalt dieser Anhänge volltext-durchsuchbar ohne den normalen Mail-Eingang zu verlangsamen.

User Stories

  • Als Nutzer möchte ich in archivierten Rechnungs-PDFs nach Beträgen oder Kundennummern suchen können.
  • Als Nutzer möchte ich eingescannte Dokumente (JPG/PNG/TIFF) im Volltext durchsuchen können.
  • Als Admin möchte ich OCR per Mandant aktivieren oder deaktivieren können.
  • Als Nutzer soll der Mail-Eingang nicht durch OCR verlangsamt werden (asynchrone Verarbeitung).

Acceptance Criteria

  • PDF-Anhänge mit eingebettetem Text: Text via pdftotext extrahieren (kein OCR nötig, schnell)
  • PDF-Anhänge ohne Text (Scan): OCR via Tesseract (deutsch + englisch)
  • Bild-Anhänge (JPG, PNG, TIFF): OCR via Tesseract
  • OCR läuft asynchron — Mail wird sofort gespeichert, OCR-Text nachgeliefert
  • OCR-Text wird in Manticore-Index im Feld attachment_text gespeichert (neues Feld)
  • Volltext-Suche findet Mails anhand von OCR-Text in Anhängen
  • OCR-Status pro Mail in PostgreSQL: ocr_status (pending / done / failed / skipped)
  • OCR kann per Mandant deaktiviert werden (ocr_enabled in tenants-Tabelle)
  • archivmail ocr-reprocess — OCR für alle oder einzelne Mandanten nachholen
  • Keine neue externe Service-Abhängigkeit bei Laufzeit — nur System-Pakete (tesseract-ocr, poppler-utils)

Edge Cases

  • Sehr große PDFs (>50 MB): Timeout nach 60s, Status failed, Mail bleibt auffindbar per Metadaten
  • Passwortgeschützte PDFs: OCR überspringen, Status skipped
  • Anhänge ohne OCR-fähiges Format (ZIP, EXE, ...): überspringen
  • Tesseract nicht installiert: OCR deaktiviert, Warnung beim Start, kein Absturz

Tech Design

Neue Komponenten

internal/ocr/ocr.go

// ExtractText extrahiert Text aus einem Anhang.
// Für PDFs: pdftotext zuerst, dann Tesseract als Fallback.
// Für Bilder: direkt Tesseract.
// Gibt leeren String zurück wenn Format nicht unterstützt oder Fehler.
func ExtractText(data []byte, contentType string, langs []string) (string, error)

// IsAvailable prüft ob Tesseract installiert ist.
func IsAvailable() bool

internal/ocr/worker.go — Async-Worker

// Worker liest aus einem Channel und verarbeitet OCR-Jobs.
// Läuft als Goroutine im Hintergrund.
type Worker struct { ... }
func NewWorker(store *storage.Store, idxMgr index.TenantIndexer) *Worker
func (w *Worker) Submit(mailID string, tenantID *int64)
func (w *Worker) Start(ctx context.Context)

DB-Schema

-- OCR-Status pro Mail
ALTER TABLE emails ADD COLUMN IF NOT EXISTS ocr_status TEXT DEFAULT 'pending';
-- Werte: pending | done | failed | skipped | disabled

-- OCR pro Tenant konfigurierbar
ALTER TABLE tenants ADD COLUMN IF NOT EXISTS ocr_enabled BOOLEAN DEFAULT TRUE;

-- Index für OCR-Queue
CREATE INDEX IF NOT EXISTS idx_emails_ocr_status ON emails (ocr_status) WHERE ocr_status = 'pending';

Manticore-Schema-Erweiterung

-- Neues Feld im RT-Index
ALTER TABLE emails_tenant_1 ADD COLUMN attachment_text text;

In internal/index/manticore.go:

  • MailDocument.AttachmentText string hinzufügen
  • ensureTable() — neues Feld im CREATE TABLE
  • IndexSync()attachment_text befüllen

Verarbeitungs-Ablauf

Mail eingehend (SMTP/IMAP/Import)
  → mailparser.Parse() → Anhänge erkannt
  → mailStore.Save() → Mail gespeichert, ocr_status = 'pending'
  → Manticore-Index ohne attachment_text
  → OCR-Worker.Submit(mailID)

OCR-Worker (async, Goroutine):
  → mailStore.Load(mailID) → Rohdaten
  → mailparser.Parse() → Anhänge
  → für jeden Anhang:
      → ocr.ExtractText(data, contentType, ["deu","eng"])
  → idxMgr.ForTenant(tenantID).UpdateAttachmentText(mailID, text)
  → mailStore.SetOCRStatus(mailID, "done")

Neues CLI-Subkommando

archivmail ocr-reprocess --config /etc/archivmail/config.yml
archivmail ocr-reprocess --config /etc/archivmail/config.yml --tenant 1
archivmail ocr-reprocess --config /etc/archivmail/config.yml --status failed

Installation auf Server

apt-get install -y tesseract-ocr tesseract-ocr-deu poppler-utils
# Prüfen
tesseract --version
pdftotext -v

update.sh — optionale Installation (kein Abbruch wenn nicht verfügbar):

apt-get install -y tesseract-ocr tesseract-ocr-deu poppler-utils 2>/dev/null || true

Performance-Überlegungen

Format Tool Dauer (A4-Seite)
PDF mit Text pdftotext < 100ms
PDF als Scan Tesseract 13s
JPG (300 DPI) Tesseract 0.52s

OCR-Worker mit konfigurierbarer Worker-Anzahl (Standard: 2 Goroutinen). Keine Blockierung des Mail-Eingangs — Submit() ist non-blocking.

Nicht in Scope

  • Microsoft Word / Excel / PowerPoint direkt (nur wenn als PDF geliefert)
  • Layout-Analyse oder Tabellen-Extraktion
  • Sprachen außer Deutsch und Englisch (erweiterbar via Config)
  • Cloud-OCR-Services (bewusst: nur lokale Tools)

Tech Design

Vollständig oben beschrieben

QA Test Results

To be added

Deployment

To be added