Werkzeug für vollständigen Suchindex-Neuaufbau: neue Tabelle anlegen,
Dokumente aus der lebenden Tabelle kopieren, Trefferzahlen verifizieren,
erst dann per Manticore RENAME atomar umschalten.
- reindex.go: Reindexer.Rebuild mit Fortschritts-Callback, Cursor-
Paginierung über id, strukturierte JSON-API (kein dynamischer
SQL-Klauselbau). Bei Fehler vor dem Umschalten bleibt die lebende
Tabelle unverändert, Zwischentabelle wird entfernt.
- Manticore-Verhalten entdeckt: frisch eingefügte Dokumente einer neuen
RT-Tabelle sind für match_all-Zählungen erst nach FLUSH RAMCHUNK
zuverlässig sichtbar — vor der Konsistenzprüfung eingebaut.
- Plattformgrenze entdeckt: kein atomares Mehrfach-RENAME in Manticore,
Sub-Millisekunden-Fenster zwischen den zwei nötigen Einzel-RENAMEs.
Client.Search bekam einen begrenzten Retry auf "unknown local table".
- Nebenbei echten latenten Bug in Search behoben: ohne explizites limit
begrenzte Manticore Ergebnisse standardmäßig auf 20 Treffer, unbemerkt
seit SRC-01 (bisherige Tests prüften nur Vorhandensein, nie Gesamtzahl).
Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-09-PRUEFPROTOKOLL.md):
1. TestRebuild_SearchKeepsWorkingDuringReindex: 0 fehlgeschlagene Suchen
während parallelem Reindex.
2. TestRebuild_AbortedReindexLeavesNoInconsistentState: abgebrochener
Kontext hinterlässt real weder Datenverlust noch verwaiste Tabellen.
3. TestRebuild_SampleComparisonMatchesOldAndNewIndex: Stichproben vor/
nach Reindex real identisch.
Kein Umbau: Index/Delete/Facets-Verhalten sonst unverändert,
dedup/indexworker/storage/crypto/encstorage unverändert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
Facetten- und Filter-API für Suche (Absender, Zeitraum, Postfach,
Anhangstyp, Tag), mandantengetrennt, mit UND-Verknüpfung mehrerer Filter.
- migrations/0002..0005: vier nummerierte ALTER-Migrationen für die neuen
Facettenfelder (Manticore erlaubt nur eine Spalte je ALTER-Anweisung),
EnsureSchema wendet sie idempotent nach.
- fields.go: FacetFields-Whitelist, einzige zulässige Facettendimensionen.
- facets.go: Client.Facets nutzt Manticores strukturierte aggs.terms/
aggs.range-API, kein dynamischer SQL-Klauselbau. Filter kombinieren als
zusätzliche equals-Klauseln in derselben bool.must-Liste wie der
Tenant-Filter. Zeitraum-Facette über feste Buckets via aggs.range.
Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-05-PRUEFPROTOKOLL.md):
1. TestFacets_CountsMatchActualHits: Facettenzahlen stimmen real mit der
tatsächlichen Treffermenge überein.
2. TestFacets_ThreeFiltersCombineWithAND: 3 kombinierte Filter schränken
4 Dokumente real auf genau 1 verbleibenden Treffer ein.
3. TestFacets_TenantSeparation: Facetten eines Mandanten enthalten real
keine Werte eines anderen.
Kein Umbau: Search/Delete/Index-Verhalten aus SRC-01/SRC-03 unverändert,
dedup/indexworker/storage/crypto/encstorage unverändert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
Indexierungs-Worker, der neu archivierte Mails asynchron in den
Manticore-Index (SRC-01) einpflegt und Löschungen nachzieht.
- indexworker/queue.go: Postgres-Jobqueue (mail_index_jobs), FOR UPDATE
SKIP LOCKED, Stale-Lock-Wiedervorlage bei Worker-Absturz, arithmetischer
Backoff bei Fail (kein String-Concat für Intervalle) — Konvention aus
dms/internal/jobqueue (FDN-04), hier bewusst ohne DLQ (nicht Bestandteil
der Akzeptanzkriterien dieser Kachel).
- indexworker/worker.go: RunOnce verarbeitet index-/delete-Jobs über
search.Client.
- search: minimale Erweiterung um Client.Delete und deterministisches
DocumentID(tenantSlug, messageID), damit Index/Delete für dieselbe Mail
immer dasselbe Dokument treffen.
Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-02-PRUEFPROTOKOLL.md):
1. TestDequeue_WorkerCrashMidRunLosesNoJob: simulierter Worker-Absturz,
Job wird nach Ablauf der Stale-Lock-Frist real erneut zugestellt.
2. TestDeleteJob_RemovesMailFromSearchResults: Lösch-Job entfernt Mail
nachweislich aus Suchtreffern.
3. TestConsistency_DatabaseAndIndexMatchOnSample: DB-Job-Status und
Index-Inhalt stichprobenartig real abgeglichen.
Zusätzlich TestIndexJob_MakesMailSearchable für Akzeptanzkriterium 1.
Kein Umbau: storage/crypto/encstorage/dedup unverändert, bestehendes
SRC-01-Verhalten unverändert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ