diff --git a/features/INDEX.md b/features/INDEX.md index a64556b..06a88c9 100644 --- a/features/INDEX.md +++ b/features/INDEX.md @@ -51,6 +51,8 @@ | PROJ-33 | IMAP-Modus: Gemeinsames Archiv vs. Persönlicher Posteingang | Deployed | [PROJ-33](PROJ-33-imap-modus-shared-personal.md) | 2026-03-31 | | PROJ-34 | Retention-Policy + Löschsperre (GoBD-Compliance) | Deployed | [PROJ-34](PROJ-34-retention-policy.md) | 2026-03-31 | +| PROJ-35 | OCR & Anhang-Volltext-Indexierung | Planned | [PROJ-35](PROJ-35-ocr-anhang-volltext.md) | 2026-04-04 | + ## Next Available ID: PROJ-35 diff --git a/features/PROJ-35-ocr-anhang-volltext.md b/features/PROJ-35-ocr-anhang-volltext.md new file mode 100644 index 0000000..28ffdd9 --- /dev/null +++ b/features/PROJ-35-ocr-anhang-volltext.md @@ -0,0 +1,159 @@ +# 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`** +```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 +```go +// 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 + +```sql +-- 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 + +```sql +-- 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 + +```bash +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 + +```bash +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): +```bash +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 | 1–3s | +| JPG (300 DPI) | Tesseract | 0.5–2s | + +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_