// Package search implementiert SRC-01: den Manticore-RT-Suchindex für // Mail-Inhalte. Bekannter Fehler vermeiden (siehe known-issues-archivmail.md // #11/#12): archivmail baute WHERE-Klauseln und teils Spalten-/Tabellennamen // dynamisch über fmt.Sprintf/strings.Join zusammen. Für dieses Paket gilt // verbindlich: Spalten- und Tabellennamen kommen AUSSCHLIESSLICH aus den // Konstanten dieser Datei, nirgendwo sonst im Paket wird ein Feld- oder // Tabellenname zur Laufzeit zusammengesetzt. Suchanfragen laufen über die // strukturierte Manticore-HTTP-JSON-API (Query/Insert-Sub, kein // String-Zusammenbau von SQL), nicht über die SQL-Schnittstelle. package search import "hash/fnv" // IndexName ist der einzige Ort, an dem der Manticore-Indexname als // Literal steht. const IndexName = "mail_documents" // Statische Feld-Whitelist des mail_documents-Index (muss deckungsgleich // mit migrations/0001_mail_documents.sql bleiben). const ( FieldTenantSlug = "tenant_slug" FieldMessageID = "message_id" FieldSubject = "subject" FieldBody = "body" FieldAttachmentText = "attachment_text" FieldSentAt = "sent_at" ) // searchableTextFields sind die Volltextfelder, über die eine Suchanfrage // läuft (Akzeptanzprüfung 3: Volltextsuche liefert erwartete Treffer). var searchableTextFields = []string{FieldSubject, FieldBody, FieldAttachmentText} // DocumentID berechnet deterministisch die Manticore-Dokument-ID aus // Mandant und Message-ID (FNV-1a, 64 Bit). Deterministisch statt einer // separat vergebenen ID, damit Re-Indexierung (Index) und Löschung // (Delete) für dieselbe Mail immer dieselbe Dokument-ID referenzieren, // ohne dass der Aufrufer sie zwischenspeichern muss (SRC-02: Löschungen // müssen ohne zusätzlichen Zustand nachgezogen werden können). func DocumentID(tenantSlug, messageID string) uint64 { h := fnv.New64a() _, _ = h.Write([]byte(tenantSlug)) _, _ = h.Write([]byte{0}) _, _ = h.Write([]byte(messageID)) return h.Sum64() }