feat: implement advanced tagging system, tag weighting, and app focus refactoring

- Implemented reusable TagSelector component with i18n support
- Added tag weighting system (popularity scores 1-5)
- Created admin panel for tag management
- Integrated Nebius AI and Brave Search for 'Magic Scan'
- Refactored app focus: removed bottle status, updated counters, and displayed extended bottle details
- Updated i18n for German and English
- Added database migration scripts
This commit is contained in:
2025-12-19 12:58:44 +01:00
parent 9eb9b41061
commit b2a1d292da
30 changed files with 2420 additions and 194 deletions

114
.nebiusbravetasks Normal file
View File

@@ -0,0 +1,114 @@
# IMPLEMENTIERUNGS-PLAN: Whisky Scanner App
## Stack: Next.js | Supabase | Nebius AI | Brave Search | Coolify
---
### 1. SICHERHEIT & INFRASTRUKTUR (Fundament)
**Ziel:** Sicherstellen, dass keine API-Keys leaken und keine User-Daten direkt an US-Anbieter fließen.
- [ ] **Environment Variablen säubern**
- Prüfe deine `.env` Datei.
- [ ] `NEBIUS_API_KEY`: Darf NICHT mit `NEXT_PUBLIC_` beginnen.
- [ ] `BRAVE_API_KEY`: Darf NICHT mit `NEXT_PUBLIC_` beginnen.
- [ ] `SUPABASE_SERVICE_ROLE_KEY`: Darf NICHT mit `NEXT_PUBLIC_` beginnen (für Admin-Schreibrechte).
- [ ] `NEXT_PUBLIC_SUPABASE_ANON_KEY`: Darf öffentlich sein (nur für RLS Lesezugriffe).
- [ ] **Server-Side Architektur erzwingen**
- Stelle sicher, dass alle Aufrufe zu Nebius und Brave ausschließlich über **Server Actions** (`'use server'`) oder **API Routes** (`app/api/...`) laufen.
- *Test:* Öffne die Entwicklertools im Browser (Netzwerk-Tab). Beim Scannen darf KEIN Aufruf zu `api.brave.com` oder `api.studio.nebius.ai` sichtbar sein. Nur Aufrufe zu deinem eigenen Backend (localhost/deine-domain).
- [ ] **Supabase Admin Client einrichten**
- Erstelle eine Utility-Datei (z.B. `lib/supabase-admin.ts`), die `createClient` mit dem `SUPABASE_SERVICE_ROLE_KEY` initialisiert.
- Nutze diesen Client NUR in Server Actions für das Schreiben in den globalen Cache.
---
### 2. NEBIUS AI STUDIO (Das "Auge")
**Ziel:** Bildanalyse und Extraktion strukturierter Daten für ca. 0,03 Cent pro Bild.
- [ ] **OpenAI SDK konfigurieren**
- Installiere das SDK: `npm install openai`
- Initialisiere den Client in `lib/ai-client.ts`:
```typescript
import { OpenAI } from "openai";
export const aiClient = new OpenAI({
baseURL: "[https://api.studio.nebius.ai/v1](https://api.studio.nebius.ai/v1)",
apiKey: process.env.NEBIUS_API_KEY,
});
```
- [ ] **Prompt Engineering (JSON Mode)**
- Erstelle den Prompt für das Modell `Qwen/Qwen2.5-VL-72B-Instruct` (oder Qwen2-VL-72B).
- Anweisung: "Extrahiere: Distillery, Name/Edition, Age/Vintage, ABV. Formatiere als reines JSON."
- WICHTIG: Setze `response_format: { type: "json_object" }` im API-Call, damit du valides JSON erhältst.
- [ ] **Such-Query Generierung**
- Lass die AI zusätzlich ein Feld `search_string` generieren.
- Format-Vorgabe an AI: `"site:whiskybase.com [Distillery] [Name] [Vintage]"`
- *Grund:* Das spart Logik im Code, die AI weiß am besten, was auf dem Etikett wichtig ist.
Bitte für den Adminuser einen Schalter zwischen Gemini und Nebius implementieren. Idealerweise im Magic Scan Formular.
---
### 3. BRAVE SEARCH API (Der "Notfall-Plan")
**Ziel:** Finden der Whiskybase-ID, wenn der Cache leer ist (Prepaid, keine Fixkosten).
- [ ] **Fetch-Funktion bauen**
- Erstelle eine Server-Funktion, die Brave aufruft.
- URL: `https://api.search.brave.com/res/v1/web/search?q=...`
- Header: `X-Subscription-Token: process.env.BRAVE_API_KEY`
- [ ] **Ergebnis-Parser implementieren**
- Nimm das erste Ergebnis (`results[0]`).
- Prüfe per Regex, ob der Link valide ist: `whiskybase.com/whiskies/whisky/([0-9]+)/...`
- Extrahiere die ID (z.B. "12345").
- [ ] **Fallback-Logik**
- Wenn Brave nichts findet (array leer), gib einen Fehler zurück oder markiere das Produkt als "Manuelle Prüfung nötig".
---
### 4. DATENBANK & CACHING (Die "Spar-Maschine")
**Ziel:** Suchkosten minimieren und Datenqualität sichern.
- [ ] **Datenbank-Schema (Tabelle `global_products`)**
- `id`: uuid (PK)
- `wb_id`: text (Whiskybase ID, unique)
- `full_name`: text (z.B. "Lagavulin 16")
- `search_vector`: tsvector (Für unscharfe Suche!)
- `image_hash`: text (Optional, falls du Hash-Vergleiche machst)
- `created_at`: timestamp
- [ ] **Row Level Security (RLS) Policies**
- Tabelle `global_products`:
- Policy "Enable Read Access for all users": `true` (für SELECT).
- Policy "Disable Insert/Update for users": `false` (für INSERT/UPDATE).
- *Grund:* Nur dein Server (Service Role) darf hier schreiben, um "Cache Poisoning" durch User zu verhindern.
- [ ] **Der "Main Loop" (Server Action)**
1. **AI:** Bild an Nebius -> JSON erhalten.
2. **DB Check:** Suche in `global_products` mit `.textSearch('search_vector', ai_name)`.
3. **Entscheidung:**
- *Treffer:* Nimm ID aus DB (Kosten: 0€). Return an Client.
- *Kein Treffer:* Rufe Brave Search auf (Kosten: 0,3 Cent).
4. **Cache Write:** Wenn Brave erfolgreich war, nutze `supabaseAdmin`, um den neuen Whisky in `global_products` zu speichern.
---
### 5. DSGVO / PRIVACY CHECKLISTE
**Ziel:** Rechtssicherer Betrieb in der EU.
- [ ] **Data Minimization**
- Schicke an Brave NUR den Suchstring (z.B. "Lagavulin 16").
- Schicke NIEMALS User-IDs, E-Mails oder IP-Adressen im Header oder Body an Brave.
- [ ] **Proxy-Check**
- Bestätige nochmals, dass Brave nur die IP deines Hetzner-Servers sieht, nie die des Endnutzers (siehe Punkt 1).
- [ ] **Nebius Region**
- Prüfe im Nebius Dashboard, dass dein Projekt in der Region **eu-north1** (Finnland) oder einer anderen EU-Region läuft, falls wählbar.