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

160 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 | 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_