# eh-search — Site-Search für electric-horses.de **Live:** Via Nginx-Proxy auf `https://www.electric-horses.de/api/search?q=...` **Interne Adresse:** `http://10.0.0.8:8200` (privat, nicht public!) **Stack-Pfad:** `/opt/ai-apps/eh-search/` auf ai-apps ## Was macht das? Ein FastAPI-Service der eine **Cmd+K Command Palette** auf der Electric-Horses-Website mit Suchergebnissen versorgt. Durchsucht: - 75 Fahrzeuge (Postgres FTS + Fuzzy + Komm-Nr/DVN Exact Lookup) - 28 Blog-Posts (mit Tags + neue SEO-Descriptions) - 24 Marken - 6 Legal-Pages (Impressum, Datenschutz, ...) - 8 Static Pages (Werkstatt, Ersatzteile, Kontakt, ...) - 60 Tag → Page Bridges für semantische Verbindungen **Killer-Feature:** Eingabe einer 4-stelligen Komm-Nr (oder `D9094` etc.) → Direct Redirect zur Fahrzeug-Detailseite. Latenz <50ms. Ideal für Mitarbeiter am Telefon. ## Architektur ``` Browser Cmd+K ↓ www.electric-horses.de/api/search ↓ (Nginx Proxy auf Pegasus) 10.0.0.8:8200 (eh-search auf ai-apps, privat) ↓ ├─ Postgres eh_vehicles (loco-replica-db Container, Port 5433) ├─ Redis Cache (Stack-intern) ├─ Directus REST API (in-memory Content Index) └─ Static Page Registry (hardcoded in Python) ``` ## Sicherheit - **Bind NUR auf privates Netz** (10.0.0.8:8200) — nicht über Public-IP erreichbar - **Read-Only DB-User** (`search_read`) — kann nur SELECT auf Materialized View - **Same-Origin via Pegasus Nginx** — kein CORS nötig, kein neues Cert, kein neues DNS - **Rate Limit** via Nginx (30 req/s pro IP) ## Files - `docker-compose.yml` — Stack - `Dockerfile` — Python 3.12 + FastAPI + asyncpg + redis-py - `requirements.txt` — Python-Deps - `.env.example` — Template für `.env` (niemals echte `.env` committen!) - `app/` — FastAPI-Anwendung - `sql/` — Postgres-Schema und Migrations (search_vehicles Materialized View, pg_trgm, unaccent) - `Agent.md` — AI-Briefing - `README.md` — diese Datei ## Live-Update-Workflow Wenn sich Fahrzeugdaten ändern (vehicle_sync.py nächtlich auf Pegasus), wird am Ende des Syncs automatisch die Materialized View refreshed UND der Redis-Cache invalidiert. Directus-Edits an Blog/Brands/Pages feuern einen Webhook an eh-search → sofortige Cache-Invalidation und Content-Index-Refresh. ## OpenProject Phasen (alle abgeschlossen) - **M6** — Postgres FTS + Fuzzy + Exact + Command Palette (Phase 1) - **M6.2** — Federated Multi-Source (Phase 1.5) - **M6.3** — UX Refinement (sleek, mobile-first, smart group ordering) - **M6.4** — Komm-Nr Datenmodell-Fix (D9094 korrekt statt falsche interne Nummer) - **M6.5** — Sync-Fix für deaktivierte Fahrzeuge ## Out of Scope (mögliche Phase 2) - Semantic Vector Search via Qdrant + bge-Embeddings - Voice Input via Whisper - LLM Filter-Extraktion via lokales Mistral/Gemma - Image Search / OCR - Cross-Encoder Reranking