# 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 (von–bis), 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 ← von–bis 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_