electric-horses-infra/stacks/eh-search/README.md

64 lines
2.8 KiB
Markdown
Raw Permalink Normal View History

# 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