# Laravel LLM Gateway - Korrekte Architektur-Umsetzung **Datum:** 2025-11-18 **Status:** 🎯 Klarstellung der Architektur-Vision --- ## πŸ—οΈ Architektur-Konzept (KORREKT) ### Zwei getrennte User-Typen: #### 1. **Admins** (`users` Tabelle) - **Zweck:** Verwaltung des Gateway-Systems - **Zugriff:** Laravel Web-Interface (Session-basiert) - **Funktionen:** - Gateway-Users verwalten - Budgets konfigurieren - Usage-Logs einsehen - Model-Pricing pflegen - Provider-Credentials fΓΌr Gateway-Users konfigurieren #### 2. **Gateway-Users** (`gateway_users` Tabelle) - **Zweck:** API-Clients (externe Anwendungen) - **Zugriff:** REST API via API-Keys - **Funktionen:** - Chat-Completions anfragen - Antworten von LLM-Providern erhalten - Innerhalb ihres Budgets arbeiten **Das ist eine saubere Trennung - so sollte es sein!** βœ… --- ## πŸ”΄ Aktuelles Problem Die API-Implementation verwendet die **falschen Tabellen**: ### Was der Code aktuell macht: ```php // ChatCompletionController.php Route::middleware('auth:sanctum')->group(function () { Route::post('/chat/completions', ...); }); // Verwendet: $user = $request->user(); // ← Aus 'users' Tabelle (Admins!) $credential = UserProviderCredential::where('user_id', $user->id)->first(); ``` ### Was der Code machen sollte: ```php // API-Key Authentication fΓΌr gateway_users Route::middleware('auth:api')->group(function () { Route::post('/chat/completions', ...); }); // Sollte verwenden: $gatewayUser = $request->user(); // ← Aus 'gateway_users' Tabelle $credential = GatewayUserCredential::where('gateway_user_id', $gatewayUser->id)->first(); ``` --- ## πŸ“‹ Umsetzungsplan ### Phase 1: Datenbank-Struktur anpassen #### 1.1 Neue Migration: Provider-Credentials fΓΌr Gateway-Users **Aktuell:** `user_provider_credentials` hat Foreign Key zu `users` **Neu:** Credential-Tabelle fΓΌr `gateway_users` erstellen ```php // Migration: create_gateway_user_credentials_table.php Schema::create('gateway_user_credentials', function (Blueprint $table) { $table->id(); $table->string('gateway_user_id'); // ← Foreign Key zu gateway_users $table->string('provider'); // openai, anthropic, google, deepseek, mistral $table->text('api_key'); // VerschlΓΌsselt $table->string('organization_id')->nullable(); $table->boolean('is_active')->default(true); $table->timestamp('last_used_at')->nullable(); $table->timestamp('last_tested_at')->nullable(); $table->string('test_status')->nullable(); // success, failed $table->text('test_error')->nullable(); $table->timestamps(); $table->foreign('gateway_user_id') ->references('user_id') ->on('gateway_users') ->onDelete('cascade'); $table->unique(['gateway_user_id', 'provider']); $table->index('is_active'); }); ``` #### 1.2 Budget-Tabelle vereinheitlichen **Entscheidung:** Welche Tabelle behalten? **Option A:** `budgets` Tabelle behalten (aktuell fΓΌr gateway_users) ```sql -- budgets Tabelle hat bereits: - id, name, monthly_limit, current_spending, alert_threshold - Keine direkte User-Zuordnung (wird ΓΌber gateway_users.budget_id verknΓΌpft) ``` **Option B:** Direkte Budget-Felder in `gateway_users` ```sql ALTER TABLE gateway_users ADD COLUMN monthly_budget_limit DECIMAL(10,2); ALTER TABLE gateway_users ADD COLUMN current_month_spending DECIMAL(10,2); ALTER TABLE gateway_users ADD COLUMN budget_alert_threshold INT; ``` **Empfehlung:** Option B - Vereinfachung - Direkter Zugriff auf Budget pro User - Weniger Joins - Einfacheres Datenmodell #### 1.3 Usage-Logging konsolidieren **Aktuell:** Zwei Tabellen: - `llm_requests` (von API-Code genutzt) - `usage_logs` (im Admin-Interface angezeigt) **Neu:** Nur `usage_logs` verwenden, aber anpassen: ```php Schema::table('usage_logs', function (Blueprint $table) { // Stelle sicher dass alle Felder vorhanden sind: // user_id β†’ gateway_user_id umbenennen $table->renameColumn('user_id', 'gateway_user_id'); // Falls fehlt: if (!Schema::hasColumn('usage_logs', 'request_payload')) { $table->json('request_payload')->nullable(); } if (!Schema::hasColumn('usage_logs', 'response_payload')) { $table->json('response_payload')->nullable(); } if (!Schema::hasColumn('usage_logs', 'ip_address')) { $table->string('ip_address')->nullable(); } if (!Schema::hasColumn('usage_logs', 'user_agent')) { $table->string('user_agent')->nullable(); } }); ``` --- ### Phase 2: API-Key Authentication System #### 2.1 Custom Guard fΓΌr API-Keys Laravel kann mit Custom Guards arbeiten. Wir erstellen einen `api-key` Guard: **config/auth.php:** ```php 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', // ← FΓΌr Admins ], 'api' => [ 'driver' => 'api-key', // ← Custom Guard 'provider' => 'gateway_users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], 'gateway_users' => [ 'driver' => 'eloquent', 'model' => App\Models\GatewayUser::class, ], ], ``` #### 2.2 API-Key Guard Implementation **Neue Datei: `app/Auth/ApiKeyGuard.php`** ```php provider = $provider; $this->request = $request; } public function user() { if ($this->user !== null) { return $this->user; } // Get API key from header: Authorization: Bearer sk-xxx $apiKey = $this->request->bearerToken(); if (!$apiKey) { return null; } // Find API key in database $keyRecord = ApiKey::where('key_prefix', substr($apiKey, 0, 10)) ->where('is_active', true) ->first(); if (!$keyRecord) { return null; } // Verify full key hash if (!Hash::check($apiKey, $keyRecord->key_hash)) { return null; } // Update last used timestamp $keyRecord->update(['last_used_at' => now()]); // Return the gateway user $this->user = GatewayUser::find($keyRecord->gateway_user_id); return $this->user; } public function validate(array $credentials = []) { return $this->user() !== null; } } ``` #### 2.3 Service Provider registrieren **app/Providers/AuthServiceProvider.php:** ```php use App\Auth\ApiKeyGuard; use Illuminate\Support\Facades\Auth; public function boot(): void { Auth::extend('api-key', function ($app, $name, array $config) { return new ApiKeyGuard( Auth::createUserProvider($config['provider']), $app['request'] ); }); } ``` --- ### Phase 3: API-Code anpassen #### 3.1 Routes aktualisieren **routes/api.php:** ```php use App\Http\Controllers\Api\ChatCompletionController; // Gateway API - verwendet 'api' guard (API-Keys fΓΌr gateway_users) Route::middleware('auth:api')->group(function () { Route::post('/chat/completions', [ChatCompletionController::class, 'create']) ->middleware(['checkbudget', 'checkratelimit']); Route::get('/user', function (Request $request) { return $request->user(); // Gibt GatewayUser zurΓΌck }); }); ``` #### 3.2 GatewayUser Model erweitern **app/Models/GatewayUser.php:** ```php 'boolean', 'metadata' => 'json', 'monthly_budget_limit' => 'decimal:2', 'current_month_spending' => 'decimal:2', ]; // Relations public function apiKeys() { return $this->hasMany(ApiKey::class, 'gateway_user_id', 'user_id'); } public function credentials() { return $this->hasMany(GatewayUserCredential::class, 'gateway_user_id', 'user_id'); } public function usageLogs() { return $this->hasMany(UsageLog::class, 'gateway_user_id', 'user_id'); } // Helper methods public function isBlocked(): bool { return $this->blocked; } public function hasExceededBudget(): bool { if (!$this->monthly_budget_limit) { return false; } return $this->current_month_spending >= $this->monthly_budget_limit; } public function incrementSpending(float $amount): void { $this->increment('current_month_spending', $amount); } public function resetMonthlySpending(): void { $this->update(['current_month_spending' => 0]); } } ``` #### 3.3 Neues Model: GatewayUserCredential **app/Models/GatewayUserCredential.php:** ```php 'boolean', 'last_used_at' => 'datetime', 'last_tested_at' => 'datetime', ]; // Automatic encryption public function setApiKeyAttribute($value): void { $this->attributes['api_key'] = Crypt::encryptString($value); } public function getApiKeyAttribute($value): string { return Crypt::decryptString($value); } public function gatewayUser() { return $this->belongsTo(GatewayUser::class, 'gateway_user_id', 'user_id'); } } ``` #### 3.4 GatewayService anpassen **app/Services/LLM/GatewayService.php - Γ„nderungen:** ```php user_id) ->where('provider', $provider) ->where('is_active', true) ->first(); if (!$credential) { throw new ProviderException( "No active API credentials found for provider: {$provider}", 400 ); } $credential->update(['last_used_at' => now()]); return $credential; } private function updateUserBudget(GatewayUser $user, float $cost): void { // Budget direkt in gateway_users Tabelle $user->incrementSpending($cost); // Check if budget exceeded if ($user->hasExceededBudget()) { // TODO: Dispatch alert notification } } } ``` #### 3.5 RequestLogger anpassen **app/Services/LLM/RequestLogger.php:** ```php use App\Models\UsageLog; // ← Statt LlmRequest public function logSuccess( string $gatewayUserId, // ← Statt int $userId string $provider, string $model, array $requestPayload, array $response, array $costs, int $responseTimeMs, ?string $ipAddress = null, ?string $userAgent = null ): int { $log = UsageLog::create([ 'gateway_user_id' => $gatewayUserId, // ← GeΓ€ndert 'provider' => $provider, 'model' => $model, 'prompt_tokens' => $response['usage']['prompt_tokens'], 'completion_tokens' => $response['usage']['completion_tokens'], 'total_tokens' => $response['usage']['total_tokens'], 'cost' => $costs['total_cost'], 'request_payload' => $requestPayload, 'response_payload' => $response, 'response_time_ms' => $responseTimeMs, 'ip_address' => $ipAddress, 'user_agent' => $userAgent, 'status' => 'success', ]); return $log->id; } ``` #### 3.6 Middleware anpassen **app/Http/Middleware/CheckBudget.php:** ```php user(); // GatewayUser if ($user && $user->hasExceededBudget()) { return response()->json([ 'error' => [ 'message' => 'Budget exceeded. Please contact your administrator.', 'type' => 'budget_exceeded', 'code' => 429, 'budget_limit' => $user->monthly_budget_limit, 'current_spending' => $user->current_month_spending, ] ], 429); } if ($user && $user->isBlocked()) { return response()->json([ 'error' => [ 'message' => 'User is blocked. Please contact your administrator.', 'type' => 'user_blocked', 'code' => 403, ] ], 403); } return $next($request); } } ``` **app/Http/Middleware/CheckRateLimit.php:** ```php user(); // GatewayUser if (!$user || !$user->rate_limit_per_hour) { return $next($request); } $key = 'rate_limit:' . $user->user_id; $requests = Cache::get($key, 0); if ($requests >= $user->rate_limit_per_hour) { $ttl = Cache::get($key . ':ttl', 3600); return response()->json([ 'error' => [ 'message' => 'Rate limit exceeded. Please try again later.', 'type' => 'rate_limit_exceeded', 'code' => 429, 'limit' => $user->rate_limit_per_hour, 'current' => $requests, 'retry_after' => $ttl, ] ], 429); } // Increment counter Cache::put($key, $requests + 1, 3600); if ($requests == 0) { Cache::put($key . ':ttl', 3600, 3600); } return $next($request); } } ``` --- ### Phase 4: Admin-Interface fΓΌr Gateway-User Credentials #### 4.1 Neuer Controller: GatewayUserCredentialController **app/Http/Controllers/Admin/GatewayUserCredentialController.php:** ```php credentials()->get(); return view('admin.gateway-user-credentials.index', compact('user', 'credentials')); } public function create($gatewayUserId) { $user = GatewayUser::findOrFail($gatewayUserId); $providers = ['openai', 'anthropic', 'google', 'deepseek', 'mistral']; return view('admin.gateway-user-credentials.create', compact('user', 'providers')); } public function store(Request $request, $gatewayUserId) { $validated = $request->validate([ 'provider' => 'required|in:openai,anthropic,google,deepseek,mistral', 'api_key' => 'required|string', 'organization_id' => 'nullable|string', ]); GatewayUserCredential::create([ 'gateway_user_id' => $gatewayUserId, 'provider' => $validated['provider'], 'api_key' => $validated['api_key'], 'organization_id' => $validated['organization_id'] ?? null, 'is_active' => true, ]); return redirect() ->route('admin.gateway-users.credentials.index', $gatewayUserId) ->with('success', 'Credential added successfully'); } // Test, Toggle, Delete methods... } ``` #### 4.2 Routes erweitern **routes/web.php - HinzufΓΌgen:** ```php Route::middleware(['auth', 'verified'])->group(function () { // ... existierende Routes ... // Gateway User Credentials Management Route::prefix('admin/gateway-users/{gatewayUser}')->name('admin.gateway-users.')->group(function () { Route::get('credentials', [GatewayUserCredentialController::class, 'index']) ->name('credentials.index'); Route::get('credentials/create', [GatewayUserCredentialController::class, 'create']) ->name('credentials.create'); Route::post('credentials', [GatewayUserCredentialController::class, 'store']) ->name('credentials.store'); Route::post('credentials/{credential}/test', [GatewayUserCredentialController::class, 'test']) ->name('credentials.test'); Route::post('credentials/{credential}/toggle', [GatewayUserCredentialController::class, 'toggle']) ->name('credentials.toggle'); Route::delete('credentials/{credential}', [GatewayUserCredentialController::class, 'destroy']) ->name('credentials.destroy'); }); }); ``` --- ## 🎯 Migrations-Reihenfolge ### Migration 1: Budget-Felder zu gateway_users hinzufΓΌgen ```bash php artisan make:migration add_budget_fields_to_gateway_users ``` ```php Schema::table('gateway_users', function (Blueprint $table) { $table->decimal('monthly_budget_limit', 10, 2)->nullable()->after('alias'); $table->decimal('current_month_spending', 10, 2)->default(0)->after('monthly_budget_limit'); $table->integer('budget_alert_threshold')->nullable()->after('current_month_spending'); $table->integer('rate_limit_per_hour')->default(60)->after('budget_alert_threshold'); $table->dropColumn('spend'); // Alte Spalte entfernen $table->dropColumn('budget_id'); // Nicht mehr gebraucht }); ``` ### Migration 2: Gateway User Credentials erstellen ```bash php artisan make:migration create_gateway_user_credentials_table ``` (Wie oben bereits dokumentiert) ### Migration 3: Usage Logs anpassen ```bash php artisan make:migration update_usage_logs_for_gateway_users ``` ```php Schema::table('usage_logs', function (Blueprint $table) { // Spalte umbenennen $table->renameColumn('user_id', 'gateway_user_id'); // Neue Spalten hinzufΓΌgen falls nicht vorhanden if (!Schema::hasColumn('usage_logs', 'request_payload')) { $table->json('request_payload')->nullable(); } if (!Schema::hasColumn('usage_logs', 'response_payload')) { $table->json('response_payload')->nullable(); } if (!Schema::hasColumn('usage_logs', 'response_time_ms')) { $table->integer('response_time_ms')->nullable(); } if (!Schema::hasColumn('usage_logs', 'ip_address')) { $table->string('ip_address', 45)->nullable(); } if (!Schema::hasColumn('usage_logs', 'user_agent')) { $table->string('user_agent')->nullable(); } }); ``` ### Migration 4: Alte Tabellen optional behalten/entfernen ```bash php artisan make:migration cleanup_old_tables ``` ```php // Optional: Diese Tabellen kΓΆnnten gelΓΆscht werden wenn nicht mehr gebraucht: // - user_provider_credentials (alte Struktur) // - user_budgets (fΓΌr users, nicht gateway_users) // - llm_requests (wenn usage_logs konsolidiert ist) // - budgets (wenn Budget jetzt in gateway_users ist) // Oder umbenennen fΓΌr Archiv: Schema::rename('user_provider_credentials', 'old_user_provider_credentials'); Schema::rename('user_budgets', 'old_user_budgets'); Schema::rename('llm_requests', 'old_llm_requests'); Schema::rename('budgets', 'old_budgets'); ``` --- ## ⏱️ Implementierungs-Zeitplan ### Tag 1-2: Datenbank & Models - βœ… Migration 1: Budget-Felder zu gateway_users - βœ… Migration 2: Gateway User Credentials Tabelle - βœ… Migration 3: Usage Logs anpassen - βœ… GatewayUser Model erweitern - βœ… GatewayUserCredential Model erstellen - βœ… ApiKey Model anpassen (falls nΓΆtig) ### Tag 3: Authentication System - βœ… ApiKeyGuard implementieren - βœ… AuthServiceProvider erweitern - βœ… config/auth.php anpassen - βœ… Middleware anpassen (CheckBudget, CheckRateLimit) - βœ… Testing: API-Key Authentication ### Tag 4: API Services anpassen - βœ… GatewayService umbauen - βœ… RequestLogger anpassen - βœ… routes/api.php anpassen - βœ… ChatCompletionController anpassen - βœ… Testing: Chat Completions Endpoint ### Tag 5: Admin-Interface - βœ… GatewayUserCredentialController erstellen - βœ… Views fΓΌr Credential-Management - βœ… Routes hinzufΓΌgen - βœ… GatewayUserController anpassen (Budget-Felder) - βœ… Testing: Admin-Interface ### Tag 6: Testing & Cleanup - βœ… Integration Tests schreiben - βœ… Ende-zu-Ende Testing - βœ… Alte Tabellen archivieren/entfernen - βœ… Dokumentation finalisieren **GeschΓ€tzter Aufwand:** 6 Arbeitstage --- ## πŸ“ Checkliste ### Datenbank - [ ] Migration: Budget-Felder zu gateway_users - [ ] Migration: Gateway User Credentials Tabelle erstellen - [ ] Migration: Usage Logs anpassen - [ ] Migration: Alte Tabellen archivieren - [ ] php artisan migrate ### Models - [ ] GatewayUser Model erweitern (Authenticatable) - [ ] GatewayUserCredential Model erstellen - [ ] UsageLog Model anpassen (gateway_user_id) ### Authentication - [ ] ApiKeyGuard implementieren - [ ] AuthServiceProvider registrieren - [ ] config/auth.php anpassen ### API - [ ] routes/api.php: auth:api statt auth:sanctum - [ ] GatewayService: GatewayUser statt User - [ ] GatewayService: GatewayUserCredential verwenden - [ ] RequestLogger: gateway_user_id verwenden - [ ] Middleware: CheckBudget anpassen - [ ] Middleware: CheckRateLimit anpassen ### Admin-Interface - [ ] GatewayUserCredentialController erstellen - [ ] Routes fΓΌr Credential-Management hinzufΓΌgen - [ ] Views erstellen fΓΌr Credential-Management - [ ] GatewayUserController: Budget-Felder anpassen ### Testing - [ ] API-Key Authentication testen - [ ] Chat Completions Endpoint testen - [ ] Budget-System testen - [ ] Rate-Limiting testen - [ ] Admin-Interface testen --- ## πŸ“Š Finale Architektur (Übersicht) ### User-Typen & Zugriff ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Laravel LLM Gateway β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Admin Users β”‚ β”‚ Gateway Users β”‚ β”‚ β”‚ β”‚ (users table) β”‚ β”‚ (gateway_users) β”‚ β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β€’ Web-Interface β”‚ β”‚ β€’ API-Zugriff β”‚ β”‚ β”‚ β”‚ β€’ Session Auth β”‚ β”‚ β€’ API-Key Auth β”‚ β”‚ β”‚ β”‚ β€’ Management β”‚ β”‚ β€’ Chat Requests β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Web-Interface β”‚ β”‚ REST API β”‚ β”‚ β”‚ β”‚ /dashboard β”‚ β”‚ /api/chat/... β”‚ β”‚ β”‚ β”‚ /gateway-users β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ /budgets β”‚ β”‚ Auth: API-Key β”‚ β”‚ β”‚ β”‚ /usage-logs β”‚ β”‚ Guard: 'api' β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Datenfluss: API-Request ``` 1. Externe App sendet Request: POST /api/chat/completions Authorization: Bearer sk-gw-abc123xyz... 2. ApiKeyGuard validiert API-Key β†’ Findet GatewayUser in gateway_users 3. Middleware: CheckBudget β†’ PrΓΌft gateway_user.monthly_budget_limit β†’ PrΓΌft gateway_user.current_month_spending β†’ PrΓΌft gateway_user.blocked 4. Middleware: CheckRateLimit β†’ PrΓΌft gateway_user.rate_limit_per_hour 5. ChatCompletionController β†’ EmpfΓ€ngt GatewayUser 6. GatewayService β†’ Holt GatewayUserCredential (Provider API-Key) β†’ Ruft LLM-Provider auf β†’ Berechnet Kosten 7. RequestLogger β†’ Speichert in usage_logs (gateway_user_id) 8. Budget Update β†’ ErhΓΆht gateway_user.current_month_spending 9. Response zurΓΌck an externe App ``` --- ## πŸ”§ Verwendungs-Beispiele ### Admin erstellt Gateway-User **Im Admin-Interface:** ``` 1. Login als Admin (users Tabelle) 2. Navigate zu: /gateway-users/create 3. Erstelle Gateway-User: - User ID: "app-customer-123" - Alias: "Customer App" - Budget: 100.00 EUR - Rate Limit: 60 requests/hour 4. Gateway-User wird in gateway_users gespeichert ``` ### Admin konfiguriert Provider-Credentials fΓΌr Gateway-User **Im Admin-Interface:** ``` 1. Navigate zu: /admin/gateway-users/app-customer-123/credentials 2. Klick auf "Add Credential" 3. WΓ€hle Provider: "OpenAI" 4. API-Key: "sk-proj-..." 5. Speichern 6. GatewayUserCredential wird erstellt (verschlΓΌsselt) ``` ### Admin generiert API-Key fΓΌr Gateway-User **Im Admin-Interface:** ``` 1. Navigate zu: /api-keys 2. Klick auf "Create API Key" 3. WΓ€hle Gateway-User: "app-customer-123" 4. Name: "Production Key" 5. System generiert: - Full Key: "sk-gw-1234567890abcdef..." - Prefix: "sk-gw-1234" - Hash wird gespeichert 6. WICHTIG: Zeige Full Key nur EINMAL an! ``` ### Externe App verwendet die API **Request:** ```bash curl -X POST http://localhost/api/chat/completions \ -H "Authorization: Bearer sk-gw-1234567890abcdef..." \ -H "Content-Type: application/json" \ -d '{ "provider": "openai", "model": "gpt-4", "messages": [ {"role": "user", "content": "Hello, how are you?"} ] }' ``` **Response:** ```json { "success": true, "request_id": 12345, "provider": "openai", "model": "gpt-4", "content": "I'm doing well, thank you for asking! ...", "role": "assistant", "finish_reason": "stop", "usage": { "prompt_tokens": 15, "completion_tokens": 20, "total_tokens": 35 }, "cost": { "prompt_cost": 0.00045, "completion_cost": 0.0012, "total_cost": 0.00165 }, "response_time_ms": 1234 } ``` --- ## βœ… Vorteile dieser Architektur 1. **Klare Trennung** - Admins (users) vs. API-Clients (gateway_users) - Verschiedene Auth-Mechanismen (Session vs. API-Key) - Verschiedene Use-Cases 2. **Sicherheit** - API-Keys sind verschlΓΌsselt und gehashed - Provider-Credentials sind verschlΓΌsselt - Budget-Limits pro Gateway-User - Rate-Limiting pro Gateway-User 3. **Skalierbarkeit** - Jeder Gateway-User kann eigene Provider-Credentials haben - Oder zentrale Admin-Credentials nutzen - Flexible Budget-Verwaltung 4. **Management** - Admins haben volle Kontrolle - KΓΆnnen Gateway-Users blockieren - KΓΆnnen Budgets anpassen - Sehen alle Usage-Logs 5. **Standard-Laravel** - Nutzt Laravel Guards (Standard-Mechanismus) - Nutzt Eloquent Models - Nutzt Laravel Migrations - Gut dokumentiert und wartbar --- ## ⚠️ Potenzielle Herausforderungen 1. **Custom Guard** - Etwas mehr Code als Sanctum - Braucht sorgfΓ€ltiges Testing **Mitigation:** Guard ist einfach und klar strukturiert 2. **API-Key Management** - API-Keys mΓΌssen sicher gespeichert werden - Nur einmal anzeigbar **Mitigation:** Standard-Pattern (wie GitHub, AWS, etc.) 3. **Migration von existierendem Code** - Mehrere Dateien mΓΌssen angepasst werden - Testing ist wichtig **Mitigation:** Systematischer Plan (6 Tage) --- ## 🎯 Zusammenfassung ### Problem erkannt: - ❌ API-Code verwendet `users` (fΓΌr Admins gedacht) - ❌ Admin-Interface verwaltet `gateway_users` (fΓΌr API-Clients) - ❌ Keine Integration zwischen beiden ### LΓΆsung: - βœ… API-Code auf `gateway_users` umstellen - βœ… Custom Guard fΓΌr API-Key Authentication - βœ… Admin-Interface fΓΌr Gateway-User Credentials - βœ… Klare Architektur: Admins vs. API-Clients ### Architektur: ``` users (Admins) └── Web-Interface (Session Auth) └── Verwalten gateway_users gateway_users (API-Clients) β”œβ”€β”€ API-Key Authentication β”œβ”€β”€ gateway_user_credentials (Provider API-Keys) β”œβ”€β”€ Budget & Rate Limits └── usage_logs ``` ### Aufwand: - **6 Arbeitstage** fΓΌr vollstΓ€ndige Umsetzung - Systematischer Plan vorhanden - Klare Checkliste ### Ergebnis: - Funktionierende API - Saubere Architektur - Standard Laravel-Patterns - Wartbar und erweiterbar --- ## πŸš€ NΓ€chste Schritte **Option A: Sofort starten (Empfohlen)** 1. Migrations erstellen und ausfΓΌhren 2. Models anpassen 3. ApiKeyGuard implementieren 4. API-Code anpassen 5. Admin-Interface erweitern 6. Testing **Option B: Erst Prototyp** 1. Nur Migrations und Models 2. Minimal-Implementierung fΓΌr Testing 3. Dann entscheiden ob weitermachen **Option C: Review und Anpassungen** 1. Plan reviewen 2. Anpassungen vornehmen 3. Dann starten --- ## πŸ“Ž Wichtige Dateien (Neu/GeΓ€ndert) ### Neu erstellen: - `app/Auth/ApiKeyGuard.php` - `app/Models/GatewayUserCredential.php` - `app/Http/Controllers/Admin/GatewayUserCredentialController.php` - `database/migrations/*_add_budget_fields_to_gateway_users.php` - `database/migrations/*_create_gateway_user_credentials_table.php` - `database/migrations/*_update_usage_logs_for_gateway_users.php` ### Anpassen: - `app/Models/GatewayUser.php` (Authenticatable implementieren) - `app/Services/LLM/GatewayService.php` (GatewayUser statt User) - `app/Services/LLM/RequestLogger.php` (gateway_user_id) - `app/Http/Middleware/CheckBudget.php` - `app/Http/Middleware/CheckRateLimit.php` - `app/Providers/AuthServiceProvider.php` - `config/auth.php` - `routes/api.php` - `routes/web.php` --- **Dokument-Ende** *Erstellt am: 2025-11-18* *Status: BEREIT FÜR IMPLEMENTIERUNG* *GeschΓ€tzter Aufwand: 6 Arbeitstage*