// 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" // Facettenfelder (SRC-05), nachgezogen über migrations/0002..0005. FieldSender = "sender" FieldMailbox = "mailbox" FieldAttachmentType = "attachment_type" FieldTag = "tag" // OCR-Sprach-/Qualitätsfelder (SRC-10), nachgezogen über // migrations/0006..0007. FieldOCRLanguage = "ocr_language" FieldOCRConfidence = "ocr_confidence" ) // FacetFields sind die je Kachel unterstützten Filterdimensionen // (Akzeptanzkriterium 1: Absender, Postfach, Anhangstyp, Tag — Zeitraum // läuft separat über FieldSentAt als Bereichsfacette, siehe facets.go). // Statische Liste — Aufrufer können ausschließlich diese Feldnamen als // Facetten-/Filterdimension angeben, kein beliebiger Client-Feldname. var FacetFields = []string{FieldSender, FieldMailbox, FieldAttachmentType, FieldTag} // 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() }