Files
archivmail/features/PROJ-6-volltext-suche.md
T
sysops 7c29ee88bd docs: vollständige README, PROJ-2 Web-Upload, PROJ-19 Mailpiler-Migration
README.md:
- Vollständige Dokumentation aller implementierten Funktionen
- Konfigurationsreferenz, Installation, Systemd, REST-API-Übersicht
- In-Progress-Features klar gekennzeichnet

PROJ-2 (EML/MBOX Web-Upload):
- POST /api/admin/upload – Multipart-Upload mit Hintergrund-Job
- GET /api/admin/upload/{jobID}/progress – Polling
- Admin-Tab "Import" mit Drag-and-Drop, Fortschrittsbalken, Abschlussbericht

PROJ-19 (Mailpiler Migration):
- archivmail import-piler mit Methoden: pilerexport | direct | auto
- Direct: AES-256-CBC + zlib mit defensiven Fallbacks
- pilerexport: Wrapper um mailpilers Export-Tool

Status-Updates: PROJ-3, PROJ-4, PROJ-6, PROJ-7, PROJ-10, PROJ-11 → Deployed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 09:23:34 +01:00

6.5 KiB
Raw Blame History

PROJ-6: Volltext-Suche & Filterung

Status: Deployed

Created: 2026-03-12 Last Updated: 2026-03-17

Dependencies

  • Requires: PROJ-1 (Authentifizierung) Suche nur für eingeloggte Nutzer
  • Requires: PROJ-5 (Speicherung & Indexierung) Suchergebnisse kommen aus dem Index

User Stories

  • Als Nutzer möchte ich nach Schlüsselwörtern suchen, damit ich relevante E-Mails schnell finden kann.
  • Als Nutzer möchte ich Suchergebnisse nach Absender, Empfänger, Datum und Anhang filtern, damit ich die Treffermenge eingrenzen kann.
  • Als Nutzer möchte ich Suchergebnisse nach Datum sortieren können (neueste/älteste zuerst).
  • Als Nutzer möchte ich Suchbegriffe in den Ergebnissen hervorgehoben sehen (Highlighting).
  • Als Nutzer sehe ich nur E-Mails, auf die ich Zugriffsrecht habe, damit Datenschutz gewahrt bleibt.

Acceptance Criteria

  • Sucheingabe mit Echtzeit-Vorschau (oder sofortiger Submit)
  • Suche in: Betreff, Absender, Empfänger, Body-Text
  • Filteroptionen: Datum (vonbis), Absender-Domain, hat Anhang (ja/nein), Label
  • Sortierung: nach Relevanz, nach Datum (auf-/absteigend)
  • Suchergebnisse paginiert (Standard: 25 pro Seite)
  • Suchbegriff in Betreff und Body-Snippet hervorgehoben
  • Suchanfragen liefern Ergebnisse in < 2 Sekunden (bei 100.000+ E-Mails)
  • Nutzer sehen nur E-Mails in ihren zugewiesenen Postfächern

Edge Cases

  • Suchanfrage ohne Ergebnisse → "Keine Ergebnisse" Meldung mit Vorschlägen
  • Sonderzeichen in Suchanfrage (", *, ?) → Escaping oder Query-Syntax erlauben
  • Suche bei sehr großem Index (1M+ Mails) → Performance-Test erforderlich
  • Gleichzeitige Suchanfragen von vielen Nutzern → kein Query-Blocking

Technical Requirements

  • Such-Engine: Xapian die Web-GUI sucht ausschließlich über den Xapian-Index
    • Kein SQL-Fulltext-Query gegen PostgreSQL DB wird nur für Metadaten-Lookup nach Treffern genutzt
    • Suchfluss: Web-GUI → API → Xapian-Query → Treffer-IDs → PostgreSQL-Metadaten-Lookup → Antwort
    • Xapian QueryParser: AND, OR, NOT, Phrasen ("exakter Text"), Wildcards (word*), Feldpräfixe (from:, subject:)
    • Relevanz-Ranking über Xapian BM25Weight
    • Snippet/Highlighting über Xapian::MSet::snippet()
    • ReadonlyDatabase für parallele Lesezugriffe (mehrere Nutzer gleichzeitig möglich)
  • Antwortzeit < 2 Sekunden für Volltext-Suche über 100.000 E-Mails
  • Suchanfragen werden für Audit-Log erfasst (optional, konfigurierbar)

Tech Design (Solution Architect)

Komponentenstruktur

Next.js Frontend:

/search
├── SearchBar                    ← Eingabefeld, Submit bei Enter oder Button
├── FilterPanel                  ← aufklappbar
│   ├── DateRangePicker          ← vonbis Datum
│   ├── DomainFilter             ← Absender-Domain Freitext
│   ├── AttachmentToggle         ← nur Mails mit Anhang
│   └── LabelFilter              ← Label-Auswahl (Mehrfachauswahl)
├── SortControls                 ← Relevanz / Datum aufsteigend / absteigend
├── ResultsList
│   └── MailCard (pro Treffer)
│       ├── Betreff (Suchbegriff hervorgehoben)
│       ├── Von / An / Datum / Größe
│       ├── Body-Snippet (Suchbegriff hervorgehoben)
│       └── Anhang-Indikator
├── Pagination                   ← Seiten-Navigation
└── EmptyState                   ← "Keine Ergebnisse" mit Suchtipps

Go Backend:

GET /api/search
├── Session Middleware            ← Auth prüfen
├── Role Filter Builder           ← user: nur eigene Postfächer / auditor: alle
├── Xapian QueryParser            ← Nutzer-Query parsen (AND/OR/NOT/Wildcards)
├── Xapian ReadonlyDatabase       ← Query ausführen, MSet zurückgeben
│   ├── BM25 Relevanz-Ranking     ← beste Treffer zuerst
│   └── MSet::snippet()           ← Highlighting-Snippets erzeugen
├── PostgreSQL Metadaten-Lookup   ← From, To, Subject, Date, Size, Attachments
└── JSON Response Assembly        ← Ergebnis zusammenbauen

Suchfluss

Next.js (Browser)                    Go Backend
      │                                   │
      │  GET /api/search                  │
      │  ?q=Rechnung&date_from=2024-01    │
      │  &has_attachments=true&page=2     │
      │ ────────────────────────────────► │
      │                            Session prüfen
      │                            Rolle ermitteln:
      │                              user   → Filter: nur eigene Postfach-IDs
      │                              auditor → kein Filter
      │                                   │
      │                            Xapian QueryParser
      │                            → Query + Datumsfilter + Anhang-Filter
      │                                   │
      │                            Xapian ReadonlyDatabase
      │                            → MSet: [doc_id_1, doc_id_5, ...]
      │                            → Snippets mit Highlighting
      │                                   │
      │                            PostgreSQL
      │                            → Metadaten für doc_ids laden
      │                                   │
      │ ◄────────────────────────────────
      │  { total, page, mails: [...] }    │
      │  MailCards rendern + highlighten  │

Technische Entscheidungen

Entscheidung Begründung
Xapian für alles, kein SQL-Fulltext Optimiert für Volltext PostgreSQL LIKE-Suche wäre bei 100k+ Mails zu langsam
ReadonlyDatabase Beliebig viele parallele Lesezugriffe kein Blocking bei gleichzeitigen Nutzern
Rolle als Xapian-Term Postfach-ID beim Indexieren als Term gespeichert Rollenfilter läuft in Xapian, nicht nachträglich in der DB
Snippets aus Xapian MSet::snippet() hebt Suchbegriff im Originaltext hervor kein separates Rendering nötig
Paginierung über Xapian Offset Nur angefragter Seitenausschnitt zurückgegeben kein Full-Scan pro Seite
PostgreSQL nur für Metadaten Nach Xapian-Suche werden nur gefundene IDs nachgeschlagen minimale DB-Last
URL-State mit nuqs Suchparameter in der URL → Back-Button funktioniert, Suchergebnisse sind verlinkbar

QA Test Results

To be added by /qa

Deployment

To be added by /deploy