bb963a796f
- seedDefaultUsers: generiert kryptographisch zufällige Passwörter (crypto/rand) statt hartkodiertes "archivmailrockz" — Passwörter werden einmalig im Terminal angezeigt und können danach nicht wiederhergestellt werden - generateJTI: verwendet crypto/rand (16 Byte, hex) statt time.UnixNano XOR deadbeef Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
129 lines
6.5 KiB
Markdown
129 lines
6.5 KiB
Markdown
# PROJ-6: Volltext-Suche & Filterung
|
||
|
||
## Status: In Review
|
||
**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_
|