Diese Datei dokumentiert den aktuellen Zustand des Projekts nach dem OpenRouter-Integration & Admin-UI-Refactoring. Sie dient als Ausgangspunkt für spätere Optimierungen.
- Branch:
master - Commit:
91a470efeat(providers): dynamic OpenRouter model sync (200+ models) - Vorhergehend:
a41ef14refactor(providers): complete overhaul of provider configuration UId8b4156fix(admin): sync provider toggle to provider_configs table8dc7637fix(health): nil pointer panic when ENCRYPTION_KEY is not set225ebfcfix(admin-ui): mount Svelte 5 with mount() instead of new App()
| Container | Status | Port | Image |
|---|---|---|---|
| llm-proxy-backend | ✅ Healthy | 127.0.0.1:8080 | latest |
| llm-proxy-admin-ui | ✅ Healthy | 127.0.0.1:3005 | latest |
| llm-proxy-postgres | ✅ Healthy | 127.0.0.1:5433 | postgres:14 |
| llm-proxy-redis | ✅ Healthy | 127.0.0.1:6380 | redis:7 |
| llm-proxy-grafana | ✅ Healthy | 127.0.0.1:3002 | grafana |
| llm-proxy-prometheus | ✅ Healthy | 127.0.0.1:9092 | prometheus |
Reverse Proxy: Caddy auf scrubgate.tech → 127.0.0.1:3005 (Admin UI) / 127.0.0.1:8080 (API)
-
Neuer Client:
internal/infrastructure/providers/openrouter/client.go- OpenAI-kompatible API (
/chat/completions) - OpenRouter-Header:
HTTP-Referer,X-Title - SSE-Streaming (OpenRouter liefert schon OpenAI-Format)
ListModels(),Health(),GetAPIKey()(maskiert)CreateMessage(),CreateMessageStream()
- OpenAI-kompatible API (
-
ProviderManager (
manager.go):openrouterStates []*clientStatefür weighted load balancingGetOpenRouterClient()mit weighted round-robin + RPM-LimitingDetermineProvider()routetopenrouter:-Prefix, unknown models → OpenRouterGetProviderKeyCounts()gibt Config-Key-Anzahl zurückReloadKeys()supportet Hot-Reload für OpenRouter
-
ChatHandler (
chat_handler.go):handleOpenRouterCompletion()— Non-Streaming (klont Request vor Mutation)handleOpenRouterStreamingCompletion()— SSE-Piping direkt durch- Prefix-Strip: entfernt
openrouter:vor dem Senden
-
ModelsHandler (
models_handler.go):- Lädt jetzt auch OpenRouter-Modelle
getProviderFromModelName()erkenntopenrouter:undabacus:Präfixe
-
ModelSyncService (
model_sync_service.go):- 16 populäre OpenRouter-Modelle hardgecoded (Claude, GPT, Llama, DeepSeek, Grok, Gemini)
- DB-Sync erfolgreich: 26 neue Models eingelesen
SyncProviderModelsfragt jetzthttps://openrouter.ai/api/v1/modelsab- Built-in providers (Claude, OpenAI) nutzen weiterhin hardcoded Liste
- Ergebnis: 386 OpenRouter-Modelle in der Datenbank (statt 16)
- Karte pro Provider: Icon, Name, Typ-Label, Build-in-Badge
- Zwei Status-Pills:
- 🟢 Enabled / 🔴 Disabled (ob der Provider aktiv ist)
- 🟢 Healthy / 🔴 Unhealthy / ⚪ Unknown (Health-Check-Status)
- 4 Statistiken: Models | DB Keys | Config Keys | Routing
- Built-in Badge für Claude/OpenAI → Disable-Button ist deaktiviert
- Saubere Modals: Test, Models, Keys
- Getrennte Key-Anzeige:
db_keys(verschlüsselt in DB) vsconfig_keys(aus config.yaml)
- nil pointer panic in Health Checker (wenn ENCRYPTION_KEY nicht gesetzt)
- Provider Toggle synchronisiert jetzt beide Tabellen (
provider_configs+provider_settings) - Svelte 5 Mount —
new App()→mount(App, ...)(hat weißen Screen verursacht) - Admin API Key Trim in
stores.js(Whitespace-Probleme) - API Key Masking in Logs
- unchecked json.Encode in Admin/Filter Handlern
- OAuth Refresh Scope Escalation
- ReDoS Detection für Content Filter Regex
- ResponseWriter.Unwrap() für Middleware-Kompatibilität
- Problem: Health Check schreibt nach
provider_configs.health_status, aberGetProviderDetailsliest von dort. Der Health Checker crasht aber manchmal bei nilproviderAPIKeyRepo. - File:
internal/application/health/provider_health_checker.go - Fix-Status: ✅ nil-check hinzugefügt, aber
UpdateHealthStatusbraucht robustes Error Handling
- Problem: Wenn man "Sync Models" mehrfach klickt, werden OpenRouter-Modelle nicht mehrfach eingefügt (UNIQUE Constraint auf
(provider_id, model_id)), aberskipped_countkönnte genauer sein. - File:
internal/interfaces/api/provider_management_handler.go
- Problem: Docker Build schreibt neue JS-Hashes, aber Browsercache/Caddy hält alte Referenzen.
- Workaround:
--no-cacheBuild +docker rm -fstattup --force-recreate - Lösung: Cache-busting Header in Caddy oder nginx config hinzufügen
- Problem:
npm ciim Docker-Build verwendet manchmal altenode_modulesLayer - Lösung: Multi-stage Build mit
npm ci --prefer-offline=false - File:
admin-ui/Dockerfile
- Problem:
\b[0-9]{5}\b(?=\s+[A-ZÄÖÜ])verwendet Lookahead(?=, wird von Go Regex nicht unterstützt - File:
internal/application/filtering/service.go - Status: Warning im Log, Filter wird übersprungen
- Status: Laufen, aber nicht für die Produktion optimiert
- User hat gesagt: "Vergiss Grafana und Prometheus"
- Problem:
config_keyszeigt nur Keys ausconfig.yaml, nicht die dynamisch in der DB gespeicherten - Erweiterung: Import-Button sollte auch
config.yamlKeys in DB migrieren können
- Ursache: Health Checker Panic → Container restart → laufende Requests broken
- Fix:
ENCRYPTION_KEYgesetzt + nil-check im Health Checker
ADMIN_API_KEYS=admin_dev_key_12345678901234567890123456789012
ENCRYPTION_KEY=39f03e83... # 32-byte AES-256 hex key
DB_PASSWORD=G5pwa5ZluH7EZdygm2zYH7pr4d6ovfbp
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=admin| Tabelle | Zweck |
|---|---|
provider_configs |
Build-time Konfiguration (name, type, enabled, health_status) |
provider_settings |
Runtime Overrides (enabled, config) — wird von Toggle geschrieben |
provider_models |
Model-Katalog (387 OpenRouter, 15 Claude, 56 OpenAI, 10 Abacus) |
provider_api_keys |
Verschlüsselte API Keys (AES-256-GCM) |
request_logs |
Request-History |
filter_matches |
Content Filter Matches |
schema_migrations.version = 1(nur Init-Migration)provider_settingswar falsch geschema (Key-Vault statt Runtime-Settings) → wurde manuell migriertprovider_configshat jetzt korrekte Spalten
-
Provider Health Checker robust machen
- Nil-checks für alle Repositories
UpdateHealthStatussollte bei fehlenden Keys nicht crashen
-
Model-Sync Vollständigkeit
- Claude/OpenAI Model-Sync von APIs abholen statt hardcoden?
- OpenRouter Sync via Cronjob/Timer statt manuell?
-
Cache-Busting fixen
- Caddy Config:
Cache-Control: no-cachefürindex.html - Oder: index.html mit
?v=<hash>referenzieren
- Caddy Config:
-
Provider API Key Import aus Config
- Button "Import Config Keys to DB" → migriert config.yaml Keys
-
Admin-UI Verbesserungen
- Responsive Design für Mobile
- Dark Mode
- Echte Health-Status-Rechtfertigung in Echtzeit
-
Monitoring
- Prometheus Metrics exportieren für LLM-Usage
- Grafana Dashboard für Provider-Health
-
Content Filter Regex #14
- Go-kompatible Alternative ohne Lookahead
(?=
- Go-kompatible Alternative ohne Lookahead
-
Tests
- Go Tests für OpenRouter Client
- Integration Tests für Provider Routing
- Frontend Tests mit Playwright
# Build Backend
docker build -t llm-proxy-backend:latest -f deployments/docker/Dockerfile .
docker save llm-proxy-backend:latest | ssh dockerfarm "docker load"
# Build Admin UI (CLEAN)
cd admin-ui
rm -rf node_modules dist package-lock.json
npm install
npm run build
docker build --no-cache -t llm-proxy-admin-ui:latest .
docker save llm-proxy-admin-ui:latest | ssh dockerfarm "docker load"
# Deploy
ssh dockerfarm "cd /opt/llm-proxy/deployments/docker && docker compose -f docker-compose.prod.yml up -d"
# Sync Models (OpenRouter dynamisch)
curl -X POST -H 'X-Admin-API-Key: admin_dev_key_...' \
https://scrubgate.tech/admin/providers/sync-models
# Verify
curl -H 'X-Admin-API-Key: admin_dev_key_...' \
https://scrubgate.tech/admin/providersLetzte Aktualisierung: 2026-05-06