{"repo": "bobprod/crm-immobilier", "files": {"docs/architecture/VISUAL_ARCHITECTURE_GUIDE.md": {"87930fe12a79617da5dd252f0a7232122f20bea7": {"t": 1785674562.347803, "n": 16934, "h": "f0f41d97a9bac653", "c": "# ๐Ÿ“ API Key Test Button - Visual Architecture\n\n## System Architecture\n\n```\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND (React/Next.js) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ โ”‚\nโ”‚ Settings Page (/settings) โ”‚\nโ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚\nโ”‚ โ”‚ API Keys Tab โ”‚ โ”‚\nโ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Google Gemini API Key [AIzaSyB6... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ โ†“ Input State โ†“ Button โ”‚ โ”‚\nโ”‚ โ”‚ apiKeyStates.gemini onClick Handlerโ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ OpenAI API Key [sk-... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ Anthropic API Key [sk-ant-... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ ... more keys ... โ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Component: renderApiKeyInput() โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Input field with password masking โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Test button with loading state โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Result display (success/error message + icon) โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Disabled state when empty โ”‚ โ”‚\nโ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Fetch Request โ”‚\nโ”‚ โ†“ โ”‚\nโ”‚ /api/api-keys/test/:provider โ”‚\nโ”‚ โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ”‚ HTTP POST\n โ”‚ JSON: { apiKey: \"...\" }\n โ”‚\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ BACKEND (NestJS) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ โ”‚\nโ”‚ API Keys Controller (NEW) โ”‚\nโ”‚ โ””โ”€ POST /api/api-keys/test/:provider โ”‚\nโ”‚ testApiKey(provider, apiKey) โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ””โ”€โ†’ SettingsService.testApiKey(provider, apiKey) โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ”œโ”€โ†’ testOpenAIKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testAnthropicKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testGeminiKey() โ† Used for your key โ”‚\nโ”‚ โ”œโ”€โ†’ testDeepseekKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testMistralKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testGrokKey() โ”‚\nโ”‚ โ””โ”€โ†’ default: Return provider not supported โ”‚\nโ”‚ โ”‚\nโ”‚ Each test method: โ”‚\nโ”‚ โ€ข Validates API key format โ”‚\nโ”‚ โ€ข Makes HTTP request to provider API โ”‚\nโ”‚ โ€ข Handles rate limiting (HTTP 429) โ”‚\nโ”‚ โ€ข Returns { success, message, provider, keyPreview } โ”‚\nโ”‚ โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ”‚ HTTP Response\n โ”‚ JSON: { success, message, ... }\n โ”‚\n โ†“\n EXTERNAL APIS\n โ”œโ”€ api.openai.com\n โ”œโ”€ api.anthropic.com\n โ”œโ”€ generativelanguage.googleapis.com โ† Gemini\n โ”œโ”€ api.deepseek.com\n โ”œโ”€ api.mistral.ai\n โ””โ”€ ... other providers\n```\n\n---\n\n## Data Flow Diagram\n\n```\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ USER INTERACTION โ”‚\nโ”‚ โ”‚\nโ”‚ 1. User enters API key in input field โ”‚\nโ”‚ [Text field]: \"AIzaSyB6ZOSlEVDIXpWdMB6...\" โ”‚\nโ”‚ โ”‚\nโ”‚ 2. User clicks \"Tester\" button โ”‚\nโ”‚ [Button]: \"Tester\" โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND STATE CHANGE โ”‚\nโ”‚ โ”‚\nโ”‚ apiKeyStates.gemini = { โ”‚\nโ”‚ apiKey: \"AIzaSyB6ZOSlEVDIXpWdMB6...\", โ† User input โ”‚\nโ”‚ testing: true, โ† Loading state โ”‚\nโ”‚ testResult: null โ† Pending โ”‚\nโ”‚ } โ”‚\nโ”‚ โ”‚\nโ”‚ UI Updates: โ”‚\nโ”‚ โ€ข Button shows spinner: \"Test... โŸณ\" โ”‚\nโ”‚ โ€ข Button is disabled โ”‚\nโ”‚ โ€ข Input field locked (readonly during test) โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ API REQUEST โ”‚\nโ”‚ โ”‚\nโ”‚ POST http://localhost:3001/api/api-keys/test/gemini โ”‚\nโ”‚ Content-Type: application/json โ”‚\nโ”‚ โ”‚\nโ”‚ { โ”‚\nโ”‚ \"apiKey\": \"AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ BACKEND PROCESSING โ”‚\nโ”‚ โ”‚\nโ”‚ 1. ApiKeysController receives POST request โ”‚\nโ”‚ 2. Calls SettingsService.testApiKey('gemini', apiKey) โ”‚\nโ”‚ 3. Routes to testGeminiKey(apiKey) โ”‚\nโ”‚ 4. Validates key format (not empty) โ”‚\nโ”‚ 5. Makes HTTPS request to Google API: โ”‚\nโ”‚ โ”‚\nโ”‚ POST https://generativelanguage.googleapis.com/v1beta/... โ”‚\nโ”‚ ?key=AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw โ”‚\nโ”‚ โ”‚\nโ”‚ 6. Receives response (could be): โ”‚\nโ”‚ โ€ข HTTP 200: Key is valid โ”‚\nโ”‚ โ€ข HTTP 400: Invalid request format (key is valid) โ”‚\nโ”‚ โ€ข HTTP 429: Rate limited (key is valid - treated as โœ“) โ”‚\nโ”‚ โ€ข HTTP 401/403: Key is invalid โ”‚\nโ”‚ โ”‚\nโ”‚ 7. Constructs response object: โ”‚\nโ”‚ { โ”‚\nโ”‚ \"success\": true, โ”‚\nโ”‚ \"message\": \"Clรฉ Gemini valide (Rate limited...)\", โ”‚\nโ”‚ \"provider\": \"gemini\", โ”‚\nโ”‚ \"keyPreview\": \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ API RESPONSE โ”‚\nโ”‚ โ”‚\nโ”‚ HTTP 200 OK โ”‚\nโ”‚ Content-Type: application/json โ”‚\nโ”‚ โ”‚\nโ”‚ { โ”‚\nโ”‚ \"success\": true, โ”‚\nโ”‚ \"message\": \"Clรฉ Gemini valide (Rate limited - API foncti...โ”‚\nโ”‚ \"provider\": \"gemini\", โ”‚\nโ”‚ \"keyPreview\": \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND STATE UPDATE โ”‚\nโ”‚ โ”‚\nโ”‚ apiKeyStates.gemini = { โ”‚\nโ”‚ apiKey: \"AIzaSyB6ZOSlEVDIXpWdMB6...\", โ”‚\nโ”‚ testing: false, โ† Loading done โ”‚\nโ”‚ testResult: { โ† Result received โ”‚\nโ”‚ success: true, โ”‚\nโ”‚ message: \"Clรฉ Gemini valide (Rate limited...)\", โ”‚\nโ”‚ provider: \"gemini\", โ”‚\nโ”‚ keyPreview: \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ”‚ } โ”‚\nโ”‚ โ”‚\nโ”‚ UI Updates: โ”‚\nโ”‚ โ€ข Button returns to \"Tester\" text โ”‚\nโ”‚ โ€ข Button becomes enabled again โ”‚\nโ”‚ โ€ข Success message displays: โ”‚\nโ”‚ โœ“ \"Clรฉ Gemini valide (Rate limited - API fonctionne)\" โ”‚\nโ”‚ โ€ข Green background with CheckCircle icon โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ USER SEES RESULT โ”‚\nโ”‚ โ”‚\nโ”‚ Google Gemini API Key [AIzaSyB6... ] [Tester] โ”‚\nโ”‚ โ”‚\nโ”‚ โœ“ Clรฉ Gemini valide (Rate limited - API fonctionne) โ”‚\nโ”‚ (Green box with CheckCircle icon) โ”‚\nโ”‚ โ”‚\nโ”‚ Status: KEY IS VALID โœ… โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n```\n\n---\n\n## Component Interaction Diagram\n\n```\nSettings Page Component\nโ”‚\nโ”œโ”€ State: activeTab = 'api-keys'\nโ”œโ”€ State: apiKeyStates = { gemini: {...}, openai: {...}, ... }\nโ”‚\nโ”œโ”€ Function: testApiKey(provider, apiKey)\nโ”‚ โ”œโ”€ Updates state: testing = true\nโ”‚ โ”œโ”€ Fetch POST /api/api-keys/test/{provider}\nโ”‚ โ””โ”€ Updates state: testResult = response\nโ”‚\nโ”œโ”€ Function: handleApiKeyChange(provider, value)\nโ”‚ โ””โ”€ Updates state: apiKey = value\nโ”‚\nโ”œโ”€ Function: renderApiKeyInput(provider, label, placeholder, description)\nโ”‚ โ”œโ”€ Input Component (type=\"password\")\nโ”‚ โ”‚ โ””โ”€ onChange โ†’ handleApiKeyChange()\nโ”‚ โ”‚\nโ”‚ โ”œโ”€ Button Component (\"Tester\")\nโ”‚ โ”‚ โ”œโ”€ onClick โ†’ testApiKey()\nโ”‚ โ”‚ โ”œโ”€ disabled = testing || !apiKey.trim()\nโ”‚ โ”‚ โ””โ”€ children = spinner or \"Tester\" text\nโ”‚ โ”‚\nโ”‚ โ””โ”€ Result Display\nโ”‚ โ”œโ”€ if testResult.success\nโ”‚ โ”‚ โ””โ”€ Green Box + CheckCircle + Success Message\nโ”‚ โ”‚\nโ”‚ โ””โ”€ if testResult.error\nโ”‚ โ””โ”€ Red Box + AlertCircle + Error Message\nโ”‚\nโ””โ”€ Render (JSX)\n โ”œโ”€ Card: \"LLM - Modรจles d'IA\"\n โ”‚ โ”œโ”€ renderApiKeyInput('openai', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('anthropic', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('gemini', ...) โ† Tested Key Here\n โ”‚ โ”œโ”€ renderApiKeyInput('deepseek', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('mistral', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('openrouter', ...)\n โ”‚ โ””โ”€ renderApiKeyInput('grok', ...)\n โ”‚\n โ””โ”€ Card: \"Moteurs de Scraping Web\"\n โ”œโ”€ Firecrawl input\n โ”œโ”€ SERP API input\n โ””โ”€ Pica input\n```\n\n---\n\n## HTTP Request/Response Examples\n\n### โœ… Successful Gemini Test\n\n**Request:**\n```http\nPOST /api/api-keys/test/gemini HTTP/1.1\nHost: localhost:3001\nContent-Type: application/json\n\n{\"apiKey\":\"AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw\"}\n```\n\n**Response:**\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"success\": true,\n \"message\": \"Clรฉ Gemini valide (Rate limited - API fonctionne)\",\n \"provider\": \"gemini\",\n \"keyPreview\": \"AIzaSyB6ZO...\"\n}\n```\n\n### โŒ Failed OpenAI Test\n\n**Request:**\n```http\nPOST /api/api-keys/test/openai HTTP/1.1\nHost: localhost:3001\nContent-Type: application/json\n\n{\"apiKey\":\"sk-invalid\"}\n```\n\n**Response:**\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"success\": false,\n \"error\": \"Incorrect API key provided: sk-invalid...\",\n \"provider\": \"openai\"\n}\n```\n\n---\n\n## UI Flow Visualization\n\n```\nDEFAULT STATE\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [ ] [Tester]\n โ†‘empty field โ†‘disabled\n\n\nUSER ENTERS KEY\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n โ†‘filled โ†‘enabled\n\n\nUSER CLICKS BUTTON\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Test...โŸณ]\n โ†‘input locked โ†‘disabled + spinner\n\n\nBACKEND VALIDATES\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n[Making request to Google API...]\n\n\nRESPONSE RECEIVED - SUCCESS\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n\nโœ“ Clรฉ Gemini valide (Rate limited - API fonctionne)\nโ† Green box with CheckCircle icon\n\n\nRESPONSE RECEIVED - ERROR\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n\nโœ— Clรฉ API invalide\nโ† Red box with AlertCircle icon\n```\n\n---\n\n## File Structure\n\n```\nbackend/\nโ””โ”€โ”€ src/\n โ””โ”€โ”€ modules/\n โ””โ”€โ”€ core/\n โ””โ”€โ”€ settings/\n โ”œโ”€โ”€ api-keys.controller.ts (NEW)\n โ”œโ”€โ”€ settings.controller.ts (modified)\n โ”œโ”€โ”€ settings.service.ts (enhanced)\n โ”œโ”€โ”€ settings.module.ts (updated)\n โ””โ”€โ”€ dto/\n โ””โ”€โ”€ ... existing DTOs ...\n\nfrontend/\nโ”œโ”€โ”€ pages/\nโ”‚ โ””โ”€โ”€ settings/\nโ”‚ โ””โ”€โ”€ index.tsx (enhanced)\nโ”‚\nโ””โ”€โ”€ tests/\n โ””โ”€โ”€ api-keys-test-button.spec.ts (NEW)\n```\n\n---\n\n## Key Technical Details\n\n### Frontend\n- **Framework**: React with Next.js\n- **State Management**: React hooks (useState)\n- **HTTP Client**: Fetch API\n- **Styling**: Tailwind CSS\n- **Icons**: Lucide React (CheckCircle, AlertCircle, Loader2)\n- **Type Safety**: TypeScript interfaces\n\n### Backend\n- **Framework**: NestJS\n- **HTTP Client**: Node.js fetch API\n- **Architecture**: Controller โ†’ Service pattern\n- **Response Format**: JSON with consistent structure\n- **Error Handling**: Try-catch blocks with graceful fallbacks\n\n---\n\n## Testing Flow (Playwright E2E)\n\n```\n1. Browser starts\n โ†“\n2. Navigate to login page\n โ†“\n3. Enter credentials and login\n โ†“\n4. Get auth token from localStorage\n โ†“\n5. Navigate to /settings\n โ†“\n6. Click API Keys tab\n โ†“\n7. Find Gemini input field\n โ†“\n8. Enter test API key\n โ†“\n9. Click Test button\n โ†“\n10. Wait for result (max 15 seconds)\n โ†“\n11. Verify success message appears\n โ†“\n12. Test passed โœ…\n```\n\n---\n\n## Summary\n\nThis architecture provides:\n- โœ… Clean separation of concerns (Frontend/Backend)\n- โœ… Secure API key handling (not stored during test)\n- โœ… Real-time user feedback\n- โœ… Extensible provider support\n- โœ… Error resilience\n- โœ… Type safety\n- โœ… Comprehensive testing\n"}, "379c58a4218ef191073dd887ca466f12266e63c5": {"t": 1785765437.8121607, "n": 16934, "h": "f0f41d97a9bac653", "c": "# ๐Ÿ“ API Key Test Button - Visual Architecture\n\n## System Architecture\n\n```\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND (React/Next.js) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ โ”‚\nโ”‚ Settings Page (/settings) โ”‚\nโ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚\nโ”‚ โ”‚ API Keys Tab โ”‚ โ”‚\nโ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Google Gemini API Key [AIzaSyB6... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ โ†“ Input State โ†“ Button โ”‚ โ”‚\nโ”‚ โ”‚ apiKeyStates.gemini onClick Handlerโ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ OpenAI API Key [sk-... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ Anthropic API Key [sk-ant-... ] [Tester] โ”‚ โ”‚\nโ”‚ โ”‚ ... more keys ... โ”‚ โ”‚\nโ”‚ โ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Component: renderApiKeyInput() โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Input field with password masking โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Test button with loading state โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Result display (success/error message + icon) โ”‚ โ”‚\nโ”‚ โ”‚ โ€ข Disabled state when empty โ”‚ โ”‚\nโ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ”‚ Fetch Request โ”‚\nโ”‚ โ†“ โ”‚\nโ”‚ /api/api-keys/test/:provider โ”‚\nโ”‚ โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ”‚ HTTP POST\n โ”‚ JSON: { apiKey: \"...\" }\n โ”‚\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ BACKEND (NestJS) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ โ”‚\nโ”‚ API Keys Controller (NEW) โ”‚\nโ”‚ โ””โ”€ POST /api/api-keys/test/:provider โ”‚\nโ”‚ testApiKey(provider, apiKey) โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ””โ”€โ†’ SettingsService.testApiKey(provider, apiKey) โ”‚\nโ”‚ โ”‚ โ”‚\nโ”‚ โ”œโ”€โ†’ testOpenAIKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testAnthropicKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testGeminiKey() โ† Used for your key โ”‚\nโ”‚ โ”œโ”€โ†’ testDeepseekKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testMistralKey() โ”‚\nโ”‚ โ”œโ”€โ†’ testGrokKey() โ”‚\nโ”‚ โ””โ”€โ†’ default: Return provider not supported โ”‚\nโ”‚ โ”‚\nโ”‚ Each test method: โ”‚\nโ”‚ โ€ข Validates API key format โ”‚\nโ”‚ โ€ข Makes HTTP request to provider API โ”‚\nโ”‚ โ€ข Handles rate limiting (HTTP 429) โ”‚\nโ”‚ โ€ข Returns { success, message, provider, keyPreview } โ”‚\nโ”‚ โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ”‚ HTTP Response\n โ”‚ JSON: { success, message, ... }\n โ”‚\n โ†“\n EXTERNAL APIS\n โ”œโ”€ api.openai.com\n โ”œโ”€ api.anthropic.com\n โ”œโ”€ generativelanguage.googleapis.com โ† Gemini\n โ”œโ”€ api.deepseek.com\n โ”œโ”€ api.mistral.ai\n โ””โ”€ ... other providers\n```\n\n---\n\n## Data Flow Diagram\n\n```\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ USER INTERACTION โ”‚\nโ”‚ โ”‚\nโ”‚ 1. User enters API key in input field โ”‚\nโ”‚ [Text field]: \"AIzaSyB6ZOSlEVDIXpWdMB6...\" โ”‚\nโ”‚ โ”‚\nโ”‚ 2. User clicks \"Tester\" button โ”‚\nโ”‚ [Button]: \"Tester\" โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND STATE CHANGE โ”‚\nโ”‚ โ”‚\nโ”‚ apiKeyStates.gemini = { โ”‚\nโ”‚ apiKey: \"AIzaSyB6ZOSlEVDIXpWdMB6...\", โ† User input โ”‚\nโ”‚ testing: true, โ† Loading state โ”‚\nโ”‚ testResult: null โ† Pending โ”‚\nโ”‚ } โ”‚\nโ”‚ โ”‚\nโ”‚ UI Updates: โ”‚\nโ”‚ โ€ข Button shows spinner: \"Test... โŸณ\" โ”‚\nโ”‚ โ€ข Button is disabled โ”‚\nโ”‚ โ€ข Input field locked (readonly during test) โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ API REQUEST โ”‚\nโ”‚ โ”‚\nโ”‚ POST http://localhost:3001/api/api-keys/test/gemini โ”‚\nโ”‚ Content-Type: application/json โ”‚\nโ”‚ โ”‚\nโ”‚ { โ”‚\nโ”‚ \"apiKey\": \"AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ BACKEND PROCESSING โ”‚\nโ”‚ โ”‚\nโ”‚ 1. ApiKeysController receives POST request โ”‚\nโ”‚ 2. Calls SettingsService.testApiKey('gemini', apiKey) โ”‚\nโ”‚ 3. Routes to testGeminiKey(apiKey) โ”‚\nโ”‚ 4. Validates key format (not empty) โ”‚\nโ”‚ 5. Makes HTTPS request to Google API: โ”‚\nโ”‚ โ”‚\nโ”‚ POST https://generativelanguage.googleapis.com/v1beta/... โ”‚\nโ”‚ ?key=AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw โ”‚\nโ”‚ โ”‚\nโ”‚ 6. Receives response (could be): โ”‚\nโ”‚ โ€ข HTTP 200: Key is valid โ”‚\nโ”‚ โ€ข HTTP 400: Invalid request format (key is valid) โ”‚\nโ”‚ โ€ข HTTP 429: Rate limited (key is valid - treated as โœ“) โ”‚\nโ”‚ โ€ข HTTP 401/403: Key is invalid โ”‚\nโ”‚ โ”‚\nโ”‚ 7. Constructs response object: โ”‚\nโ”‚ { โ”‚\nโ”‚ \"success\": true, โ”‚\nโ”‚ \"message\": \"Clรฉ Gemini valide (Rate limited...)\", โ”‚\nโ”‚ \"provider\": \"gemini\", โ”‚\nโ”‚ \"keyPreview\": \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ API RESPONSE โ”‚\nโ”‚ โ”‚\nโ”‚ HTTP 200 OK โ”‚\nโ”‚ Content-Type: application/json โ”‚\nโ”‚ โ”‚\nโ”‚ { โ”‚\nโ”‚ \"success\": true, โ”‚\nโ”‚ \"message\": \"Clรฉ Gemini valide (Rate limited - API foncti...โ”‚\nโ”‚ \"provider\": \"gemini\", โ”‚\nโ”‚ \"keyPreview\": \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ FRONTEND STATE UPDATE โ”‚\nโ”‚ โ”‚\nโ”‚ apiKeyStates.gemini = { โ”‚\nโ”‚ apiKey: \"AIzaSyB6ZOSlEVDIXpWdMB6...\", โ”‚\nโ”‚ testing: false, โ† Loading done โ”‚\nโ”‚ testResult: { โ† Result received โ”‚\nโ”‚ success: true, โ”‚\nโ”‚ message: \"Clรฉ Gemini valide (Rate limited...)\", โ”‚\nโ”‚ provider: \"gemini\", โ”‚\nโ”‚ keyPreview: \"AIzaSyB6ZO...\" โ”‚\nโ”‚ } โ”‚\nโ”‚ } โ”‚\nโ”‚ โ”‚\nโ”‚ UI Updates: โ”‚\nโ”‚ โ€ข Button returns to \"Tester\" text โ”‚\nโ”‚ โ€ข Button becomes enabled again โ”‚\nโ”‚ โ€ข Success message displays: โ”‚\nโ”‚ โœ“ \"Clรฉ Gemini valide (Rate limited - API fonctionne)\" โ”‚\nโ”‚ โ€ข Green background with CheckCircle icon โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n โ”‚\n โ†“\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ USER SEES RESULT โ”‚\nโ”‚ โ”‚\nโ”‚ Google Gemini API Key [AIzaSyB6... ] [Tester] โ”‚\nโ”‚ โ”‚\nโ”‚ โœ“ Clรฉ Gemini valide (Rate limited - API fonctionne) โ”‚\nโ”‚ (Green box with CheckCircle icon) โ”‚\nโ”‚ โ”‚\nโ”‚ Status: KEY IS VALID โœ… โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n```\n\n---\n\n## Component Interaction Diagram\n\n```\nSettings Page Component\nโ”‚\nโ”œโ”€ State: activeTab = 'api-keys'\nโ”œโ”€ State: apiKeyStates = { gemini: {...}, openai: {...}, ... }\nโ”‚\nโ”œโ”€ Function: testApiKey(provider, apiKey)\nโ”‚ โ”œโ”€ Updates state: testing = true\nโ”‚ โ”œโ”€ Fetch POST /api/api-keys/test/{provider}\nโ”‚ โ””โ”€ Updates state: testResult = response\nโ”‚\nโ”œโ”€ Function: handleApiKeyChange(provider, value)\nโ”‚ โ””โ”€ Updates state: apiKey = value\nโ”‚\nโ”œโ”€ Function: renderApiKeyInput(provider, label, placeholder, description)\nโ”‚ โ”œโ”€ Input Component (type=\"password\")\nโ”‚ โ”‚ โ””โ”€ onChange โ†’ handleApiKeyChange()\nโ”‚ โ”‚\nโ”‚ โ”œโ”€ Button Component (\"Tester\")\nโ”‚ โ”‚ โ”œโ”€ onClick โ†’ testApiKey()\nโ”‚ โ”‚ โ”œโ”€ disabled = testing || !apiKey.trim()\nโ”‚ โ”‚ โ””โ”€ children = spinner or \"Tester\" text\nโ”‚ โ”‚\nโ”‚ โ””โ”€ Result Display\nโ”‚ โ”œโ”€ if testResult.success\nโ”‚ โ”‚ โ””โ”€ Green Box + CheckCircle + Success Message\nโ”‚ โ”‚\nโ”‚ โ””โ”€ if testResult.error\nโ”‚ โ””โ”€ Red Box + AlertCircle + Error Message\nโ”‚\nโ””โ”€ Render (JSX)\n โ”œโ”€ Card: \"LLM - Modรจles d'IA\"\n โ”‚ โ”œโ”€ renderApiKeyInput('openai', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('anthropic', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('gemini', ...) โ† Tested Key Here\n โ”‚ โ”œโ”€ renderApiKeyInput('deepseek', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('mistral', ...)\n โ”‚ โ”œโ”€ renderApiKeyInput('openrouter', ...)\n โ”‚ โ””โ”€ renderApiKeyInput('grok', ...)\n โ”‚\n โ””โ”€ Card: \"Moteurs de Scraping Web\"\n โ”œโ”€ Firecrawl input\n โ”œโ”€ SERP API input\n โ””โ”€ Pica input\n```\n\n---\n\n## HTTP Request/Response Examples\n\n### โœ… Successful Gemini Test\n\n**Request:**\n```http\nPOST /api/api-keys/test/gemini HTTP/1.1\nHost: localhost:3001\nContent-Type: application/json\n\n{\"apiKey\":\"AIzaSyB6ZOSlEVDIXpWdMB6zgDvmDiC-3pxPDSw\"}\n```\n\n**Response:**\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"success\": true,\n \"message\": \"Clรฉ Gemini valide (Rate limited - API fonctionne)\",\n \"provider\": \"gemini\",\n \"keyPreview\": \"AIzaSyB6ZO...\"\n}\n```\n\n### โŒ Failed OpenAI Test\n\n**Request:**\n```http\nPOST /api/api-keys/test/openai HTTP/1.1\nHost: localhost:3001\nContent-Type: application/json\n\n{\"apiKey\":\"sk-invalid\"}\n```\n\n**Response:**\n```http\nHTTP/1.1 200 OK\nContent-Type: application/json\n\n{\n \"success\": false,\n \"error\": \"Incorrect API key provided: sk-invalid...\",\n \"provider\": \"openai\"\n}\n```\n\n---\n\n## UI Flow Visualization\n\n```\nDEFAULT STATE\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [ ] [Tester]\n โ†‘empty field โ†‘disabled\n\n\nUSER ENTERS KEY\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n โ†‘filled โ†‘enabled\n\n\nUSER CLICKS BUTTON\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Test...โŸณ]\n โ†‘input locked โ†‘disabled + spinner\n\n\nBACKEND VALIDATES\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n[Making request to Google API...]\n\n\nRESPONSE RECEIVED - SUCCESS\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n\nโœ“ Clรฉ Gemini valide (Rate limited - API fonctionne)\nโ† Green box with CheckCircle icon\n\n\nRESPONSE RECEIVED - ERROR\nโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\nGoogle Gemini API Key [AIzaSyB6... ] [Tester]\n\nโœ— Clรฉ API invalide\nโ† Red box with AlertCircle icon\n```\n\n---\n\n## File Structure\n\n```\nbackend/\nโ””โ”€โ”€ src/\n โ””โ”€โ”€ modules/\n โ””โ”€โ”€ core/\n โ””โ”€โ”€ settings/\n โ”œโ”€โ”€ api-keys.controller.ts (NEW)\n โ”œโ”€โ”€ settings.controller.ts (modified)\n โ”œโ”€โ”€ settings.service.ts (enhanced)\n โ”œโ”€โ”€ settings.module.ts (updated)\n โ””โ”€โ”€ dto/\n โ””โ”€โ”€ ... existing DTOs ...\n\nfrontend/\nโ”œโ”€โ”€ pages/\nโ”‚ โ””โ”€โ”€ settings/\nโ”‚ โ””โ”€โ”€ index.tsx (enhanced)\nโ”‚\nโ””โ”€โ”€ tests/\n โ””โ”€โ”€ api-keys-test-button.spec.ts (NEW)\n```\n\n---\n\n## Key Technical Details\n\n### Frontend\n- **Framework**: React with Next.js\n- **State Management**: React hooks (useState)\n- **HTTP Client**: Fetch API\n- **Styling**: Tailwind CSS\n- **Icons**: Lucide React (CheckCircle, AlertCircle, Loader2)\n- **Type Safety**: TypeScript interfaces\n\n### Backend\n- **Framework**: NestJS\n- **HTTP Client**: Node.js fetch API\n- **Architecture**: Controller โ†’ Service pattern\n- **Response Format**: JSON with consistent structure\n- **Error Handling**: Try-catch blocks with graceful fallbacks\n\n---\n\n## Testing Flow (Playwright E2E)\n\n```\n1. Browser starts\n โ†“\n2. Navigate to login page\n โ†“\n3. Enter credentials and login\n โ†“\n4. Get auth token from localStorage\n โ†“\n5. Navigate to /settings\n โ†“\n6. Click API Keys tab\n โ†“\n7. Find Gemini input field\n โ†“\n8. Enter test API key\n โ†“\n9. Click Test button\n โ†“\n10. Wait for result (max 15 seconds)\n โ†“\n11. Verify success message appears\n โ†“\n12. Test passed โœ…\n```\n\n---\n\n## Summary\n\nThis architecture provides:\n- โœ… Clean separation of concerns (Frontend/Backend)\n- โœ… Secure API key handling (not stored during test)\n- โœ… Real-time user feedback\n- โœ… Extensible provider support\n- โœ… Error resilience\n- โœ… Type safety\n- โœ… Comprehensive testing\n"}}, "docs/guides/TEST_API_KEYS_GUIDE.md": {"87930fe12a79617da5dd252f0a7232122f20bea7": {"t": 1785746537.1917078, "n": 6337, "h": "c1dd5ae1e9e027bb", "c": "# ๐Ÿงช Guide de Test - Clรฉs API Deepseek\n\n## โœ… Ce qui a รฉtรฉ implรฉmentรฉ\n\n### 1. **Correction du problรจme d'authentification**\n- โœ“ Crรฉรฉ une fonction `getAuthToken()` qui cherche le token dans plusieurs clรฉs localStorage:\n - `auth_token`\n - `access_token`\n - `crm-token`\n - `token`\n- โœ“ Corrigรฉ dans `loadApiKeys()` et `handleSave()`\n\n### 2. **Bouton de test pour valider les clรฉs API**\n- โœ“ Ajoutรฉ bouton \"Tester\" pour OpenAI, Gemini, DeepSeek, Anthropic\n- โœ“ Icรดne TestTube avec รฉtat loading\n- โœ“ Affiche badge \"Validรฉe\" quand la clรฉ est valide\n\n### 3. **Endpoint backend pour valider les clรฉs**\n- โœ“ Crรฉรฉ `POST /api/ai-billing/api-keys/validate`\n- โœ“ Validation pour chaque provider (OpenAI, Gemini, DeepSeek, Anthropic)\n- โœ“ Retourne les modรจles disponibles\n\n### 4. **Workflow complet**\n1. L'utilisateur entre une clรฉ API\n2. Clique sur \"Tester\"\n3. Validation effectuรฉe et modรจles retournรฉs\n4. Modรจle sรฉlectionnรฉ automatiquement\n5. Clique \"Enregistrer les clรฉs LLM\"\n6. Clรฉ et modรจle sauvegardรฉs en base de donnรฉes\n7. Page rechargรฉe avec la clรฉ affichรฉe\n\n---\n\n## ๐Ÿš€ Comment tester\n\n### **Option 1: Tests Curl (Backend)**\n\n```bash\n# 1. Aller au rรฉpertoire du projet\ncd \"c:/Users/DELL/Desktop/project dev/CRM_IMMOBILIER_COMPLET_FINAL/.git/crm-immobilier\"\n\n# 2. Lancer le script de test\nbash test-api-keys.sh\n\n# Ou tester manuellement:\n\n# 1. Authentification\ncurl -X POST http://localhost:3001/api/auth/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"test@example.com\",\"password\":\"password123\"}'\n\n# 2. Copier le token reรงu et l'utiliser comme:\nTOKEN=\"votre-token-ici\"\n\n# 3. Tester une clรฉ invalide\ncurl -X POST http://localhost:3001/api/ai-billing/api-keys/validate \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"provider\":\"deepseek\",\"apiKey\":\"invalid-key-123\"}'\n\n# 4. Tester avec une clรฉ rรฉelle (remplacer par votre clรฉ)\ncurl -X POST http://localhost:3001/api/ai-billing/api-keys/validate \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"provider\":\"deepseek\",\"apiKey\":\"sk-your-real-key\"}'\n\n# 5. Sauvegarder la clรฉ\ncurl -X PUT http://localhost:3001/api/ai-billing/api-keys/user \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"deepseekApiKey\":\"sk-your-key\",\n \"defaultProvider\":\"deepseek\",\n \"defaultModel\":\"deepseek-chat\"\n }'\n\n# 6. Rรฉcupรฉrer les clรฉs\ncurl http://localhost:3001/api/ai-billing/api-keys/user \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### **Option 2: Tests Playwright E2E (Frontend)**\n\n```bash\n# 1. Aller au rรฉpertoire frontend\ncd \"c:/Users/DELL/Desktop/project dev/CRM_IMMOBILIER_COMPLET_FINAL/.git/crm-immobilier/frontend\"\n\n# 2. Lancer le test Deepseek\nnpx playwright test tests/api-keys-deepseek.spec.ts\n\n# 3. Pour un test interactif (avec UI)\nnpx playwright test tests/api-keys-deepseek.spec.ts --ui\n\n# 4. Pour un test dans Chrome uniquement\nnpx playwright test tests/api-keys-deepseek.spec.ts --project=chromium\n\n# 5. Pour voir le rapport\nnpx playwright show-report\n```\n\n### **Option 3: Tests Manuels (Interface)**\n\n1. **Dรฉmarrer le backend et frontend**:\n ```bash\n # Terminal 1 - Backend\n cd backend\n npm run dev\n\n # Terminal 2 - Frontend\n cd frontend\n npm run dev\n ```\n\n2. **Naviguer vers la page**:\n - Ouvrir http://localhost:3000/settings/ai-api-keys\n - Connectez-vous si nรฉcessaire\n\n3. **Tester Deepseek**:\n - Cliquer sur l'onglet \"LLM / IA\"\n - Dans \"Sรฉlectionner un Provider LLM\", choisir \"DeepSeek\"\n - Remplir la clรฉ dans le champ \"DeepSeek\"\n - Cliquer le bouton \"Tester\" qui apparaรฎt\n - Attendre la validation\n - Voir le modรจle s'afficher automatiquement\n - Cliquer \"Enregistrer les clรฉs LLM\"\n - Recharger la page (F5)\n - Vรฉrifier que la clรฉ est toujours prรฉsente\n\n---\n\n## ๐Ÿ” Points de vรฉrification\n\n### Backend:\n- [ ] Endpoint `/api/ai-billing/api-keys/validate` rรฉpond correctement\n- [ ] Les rรฉponses API incluent les modรจles disponibles\n- [ ] Les clรฉs sont correctement sauvegardรฉes en base de donnรฉes\n- [ ] Endpoint `/api/ai-billing/api-keys/user/full` retourne les clรฉs complรจtes\n\n### Frontend:\n- [ ] Le bouton \"Tester\" aparaรฎt aprรจs entrer une clรฉ\n- [ ] Clique sur \"Tester\" affiche un loader\n- [ ] Toast de succรจs/erreur s'affiche\n- [ ] Badge \"Validรฉe\" apparaรฎt pour les clรฉs valides\n- [ ] Le dropdown \"Modรจle ร  utiliser\" se remplit automatiquement\n- [ ] Les clรฉs sont affichรฉes dans les inputs au chargement de la page\n- [ ] Les clรฉs sont sauvegardรฉes et persistent aprรจs rechargement\n\n### Erreurs courantes:\n- โŒ \"Authentification requise\" โ†’ Vรฉrifiez que le token est correctement rรฉcupรฉrรฉ\n- โŒ \"Clรฉ invalide\" โ†’ Testez avec une vraie clรฉ API\n- โŒ \"Erreur de connexion\" โ†’ Vรฉrifiez que le backend est lancรฉ\n- โŒ \"Modรจles non affichรฉs\" โ†’ Vรฉrifiez que la validation a rรฉussi\n\n---\n\n## ๐Ÿ“ Changements effectuรฉs\n\n### Frontend (`frontend/src/pages/settings/ai-api-keys.tsx`):\n- Ajoutรฉ `getAuthToken()` function\n- Ajoutรฉ icone `TestTube`\n- Ajoutรฉ รฉtats: `testingKeys`, `validatedKeys`, `availableModelsPerKey`\n- Ajoutรฉ fonction `handleTestApiKey()`\n- Ajoutรฉ fonction `getProviderFromKeyName()`\n- Amรฉliorรฉ `renderKeyInput()` avec bouton de test\n\n### Backend (`backend/src/modules/ai-billing/api-keys.controller.ts`):\n- Ajoutรฉ endpoint `POST /api/ai-billing/api-keys/validate`\n- Ajoutรฉ fonction `getDefaultModelsForProvider()`\n\n### Service API (`backend/src/shared/services/api-keys.service.ts`):\n- Ajoutรฉ fonction `validateApiKey()`\n- Ajoutรฉ validateurs spรฉcifiques pour chaque provider:\n - `validateOpenAIKey()`\n - `validateGeminiKey()`\n - `validateDeepseekKey()`\n - `validateAnthropicKey()`\n\n---\n\n## ๐ŸŽฏ Rรฉsultats attendus\n\nโœ… **Succรจs**:\n- Les clรฉs sont testรฉes et validรฉes\n- Les modรจles s'affichent automatiquement\n- Les clรฉs sont sauvegardรฉes en base de donnรฉes\n- Les clรฉs sont affichรฉes lors du rechargement de la page\n\nโŒ **Erreur**:\n- Message clair indiquant le problรจme\n- Possibilitรฉ de corriger et rรฉessayer\n\n---\n\n## ๐Ÿ“Š Commandes rapides\n\n```bash\n# Tester le backend rapidement\ncd backend && npm run dev &\ncd frontend && npm run dev &\n\n# Accรฉder ร  la page\nopen http://localhost:3000/settings/ai-api-keys\n\n# Lancer les tests e2e\nnpm run test:e2e\n\n# Voir les logs\nnpm run dev -- --debug\n\n# Arrรชter les serveurs\npkill -f \"npm run dev\"\n```\n\n---\n\n**Auteur**: Code Rabbit + Claude Haiku\n**Date**: Janvier 2026\n**Status**: โœ… Complet et testรฉ\n"}, "379c58a4218ef191073dd887ca466f12266e63c5": {"t": 1785765434.7890553, "n": 6337, "h": "c1dd5ae1e9e027bb", "c": "# ๐Ÿงช Guide de Test - Clรฉs API Deepseek\n\n## โœ… Ce qui a รฉtรฉ implรฉmentรฉ\n\n### 1. **Correction du problรจme d'authentification**\n- โœ“ Crรฉรฉ une fonction `getAuthToken()` qui cherche le token dans plusieurs clรฉs localStorage:\n - `auth_token`\n - `access_token`\n - `crm-token`\n - `token`\n- โœ“ Corrigรฉ dans `loadApiKeys()` et `handleSave()`\n\n### 2. **Bouton de test pour valider les clรฉs API**\n- โœ“ Ajoutรฉ bouton \"Tester\" pour OpenAI, Gemini, DeepSeek, Anthropic\n- โœ“ Icรดne TestTube avec รฉtat loading\n- โœ“ Affiche badge \"Validรฉe\" quand la clรฉ est valide\n\n### 3. **Endpoint backend pour valider les clรฉs**\n- โœ“ Crรฉรฉ `POST /api/ai-billing/api-keys/validate`\n- โœ“ Validation pour chaque provider (OpenAI, Gemini, DeepSeek, Anthropic)\n- โœ“ Retourne les modรจles disponibles\n\n### 4. **Workflow complet**\n1. L'utilisateur entre une clรฉ API\n2. Clique sur \"Tester\"\n3. Validation effectuรฉe et modรจles retournรฉs\n4. Modรจle sรฉlectionnรฉ automatiquement\n5. Clique \"Enregistrer les clรฉs LLM\"\n6. Clรฉ et modรจle sauvegardรฉs en base de donnรฉes\n7. Page rechargรฉe avec la clรฉ affichรฉe\n\n---\n\n## ๐Ÿš€ Comment tester\n\n### **Option 1: Tests Curl (Backend)**\n\n```bash\n# 1. Aller au rรฉpertoire du projet\ncd \"c:/Users/DELL/Desktop/project dev/CRM_IMMOBILIER_COMPLET_FINAL/.git/crm-immobilier\"\n\n# 2. Lancer le script de test\nbash test-api-keys.sh\n\n# Ou tester manuellement:\n\n# 1. Authentification\ncurl -X POST http://localhost:3001/api/auth/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"test@example.com\",\"password\":\"password123\"}'\n\n# 2. Copier le token reรงu et l'utiliser comme:\nTOKEN=\"votre-token-ici\"\n\n# 3. Tester une clรฉ invalide\ncurl -X POST http://localhost:3001/api/ai-billing/api-keys/validate \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"provider\":\"deepseek\",\"apiKey\":\"invalid-key-123\"}'\n\n# 4. Tester avec une clรฉ rรฉelle (remplacer par votre clรฉ)\ncurl -X POST http://localhost:3001/api/ai-billing/api-keys/validate \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"provider\":\"deepseek\",\"apiKey\":\"sk-your-real-key\"}'\n\n# 5. Sauvegarder la clรฉ\ncurl -X PUT http://localhost:3001/api/ai-billing/api-keys/user \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"deepseekApiKey\":\"sk-your-key\",\n \"defaultProvider\":\"deepseek\",\n \"defaultModel\":\"deepseek-chat\"\n }'\n\n# 6. Rรฉcupรฉrer les clรฉs\ncurl http://localhost:3001/api/ai-billing/api-keys/user \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### **Option 2: Tests Playwright E2E (Frontend)**\n\n```bash\n# 1. Aller au rรฉpertoire frontend\ncd \"c:/Users/DELL/Desktop/project dev/CRM_IMMOBILIER_COMPLET_FINAL/.git/crm-immobilier/frontend\"\n\n# 2. Lancer le test Deepseek\nnpx playwright test tests/api-keys-deepseek.spec.ts\n\n# 3. Pour un test interactif (avec UI)\nnpx playwright test tests/api-keys-deepseek.spec.ts --ui\n\n# 4. Pour un test dans Chrome uniquement\nnpx playwright test tests/api-keys-deepseek.spec.ts --project=chromium\n\n# 5. Pour voir le rapport\nnpx playwright show-report\n```\n\n### **Option 3: Tests Manuels (Interface)**\n\n1. **Dรฉmarrer le backend et frontend**:\n ```bash\n # Terminal 1 - Backend\n cd backend\n npm run dev\n\n # Terminal 2 - Frontend\n cd frontend\n npm run dev\n ```\n\n2. **Naviguer vers la page**:\n - Ouvrir http://localhost:3000/settings/ai-api-keys\n - Connectez-vous si nรฉcessaire\n\n3. **Tester Deepseek**:\n - Cliquer sur l'onglet \"LLM / IA\"\n - Dans \"Sรฉlectionner un Provider LLM\", choisir \"DeepSeek\"\n - Remplir la clรฉ dans le champ \"DeepSeek\"\n - Cliquer le bouton \"Tester\" qui apparaรฎt\n - Attendre la validation\n - Voir le modรจle s'afficher automatiquement\n - Cliquer \"Enregistrer les clรฉs LLM\"\n - Recharger la page (F5)\n - Vรฉrifier que la clรฉ est toujours prรฉsente\n\n---\n\n## ๐Ÿ” Points de vรฉrification\n\n### Backend:\n- [ ] Endpoint `/api/ai-billing/api-keys/validate` rรฉpond correctement\n- [ ] Les rรฉponses API incluent les modรจles disponibles\n- [ ] Les clรฉs sont correctement sauvegardรฉes en base de donnรฉes\n- [ ] Endpoint `/api/ai-billing/api-keys/user/full` retourne les clรฉs complรจtes\n\n### Frontend:\n- [ ] Le bouton \"Tester\" aparaรฎt aprรจs entrer une clรฉ\n- [ ] Clique sur \"Tester\" affiche un loader\n- [ ] Toast de succรจs/erreur s'affiche\n- [ ] Badge \"Validรฉe\" apparaรฎt pour les clรฉs valides\n- [ ] Le dropdown \"Modรจle ร  utiliser\" se remplit automatiquement\n- [ ] Les clรฉs sont affichรฉes dans les inputs au chargement de la page\n- [ ] Les clรฉs sont sauvegardรฉes et persistent aprรจs rechargement\n\n### Erreurs courantes:\n- โŒ \"Authentification requise\" โ†’ Vรฉrifiez que le token est correctement rรฉcupรฉrรฉ\n- โŒ \"Clรฉ invalide\" โ†’ Testez avec une vraie clรฉ API\n- โŒ \"Erreur de connexion\" โ†’ Vรฉrifiez que le backend est lancรฉ\n- โŒ \"Modรจles non affichรฉs\" โ†’ Vรฉrifiez que la validation a rรฉussi\n\n---\n\n## ๐Ÿ“ Changements effectuรฉs\n\n### Frontend (`frontend/src/pages/settings/ai-api-keys.tsx`):\n- Ajoutรฉ `getAuthToken()` function\n- Ajoutรฉ icone `TestTube`\n- Ajoutรฉ รฉtats: `testingKeys`, `validatedKeys`, `availableModelsPerKey`\n- Ajoutรฉ fonction `handleTestApiKey()`\n- Ajoutรฉ fonction `getProviderFromKeyName()`\n- Amรฉliorรฉ `renderKeyInput()` avec bouton de test\n\n### Backend (`backend/src/modules/ai-billing/api-keys.controller.ts`):\n- Ajoutรฉ endpoint `POST /api/ai-billing/api-keys/validate`\n- Ajoutรฉ fonction `getDefaultModelsForProvider()`\n\n### Service API (`backend/src/shared/services/api-keys.service.ts`):\n- Ajoutรฉ fonction `validateApiKey()`\n- Ajoutรฉ validateurs spรฉcifiques pour chaque provider:\n - `validateOpenAIKey()`\n - `validateGeminiKey()`\n - `validateDeepseekKey()`\n - `validateAnthropicKey()`\n\n---\n\n## ๐ŸŽฏ Rรฉsultats attendus\n\nโœ… **Succรจs**:\n- Les clรฉs sont testรฉes et validรฉes\n- Les modรจles s'affichent automatiquement\n- Les clรฉs sont sauvegardรฉes en base de donnรฉes\n- Les clรฉs sont affichรฉes lors du rechargement de la page\n\nโŒ **Erreur**:\n- Message clair indiquant le problรจme\n- Possibilitรฉ de corriger et rรฉessayer\n\n---\n\n## ๐Ÿ“Š Commandes rapides\n\n```bash\n# Tester le backend rapidement\ncd backend && npm run dev &\ncd frontend && npm run dev &\n\n# Accรฉder ร  la page\nopen http://localhost:3000/settings/ai-api-keys\n\n# Lancer les tests e2e\nnpm run test:e2e\n\n# Voir les logs\nnpm run dev -- --debug\n\n# Arrรชter les serveurs\npkill -f \"npm run dev\"\n```\n\n---\n\n**Auteur**: Code Rabbit + Claude Haiku\n**Date**: Janvier 2026\n**Status**: โœ… Complet et testรฉ\n"}}, "docs/guides/TROUBLESHOOTING.md": {"87930fe12a79617da5dd252f0a7232122f20bea7": {"t": 1785746542.9752643, "n": 7200, "h": "1bcff09cb22419b2", "c": "# ๐Ÿ”ง Troubleshooting - Clรฉs API Deepseek\n\n## โŒ Erreur: \"Authentification requise. Veuillez vous connecter.\"\n\n### Cause:\nLe token n'est pas trouvรฉ dans localStorage.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier que vous รชtes connectรฉ\n - Vรฉrifiez que vous avez entrรฉ vos identifiants de connexion\n - Vรฉrifiez que la session n'a pas expirรฉ\n\n# 2. Nettoyer le cache navigateur\n - DevTools > Application > Clear Site Data\n - Fermer et rouvrir le navigateur\n\n# 3. Vรฉrifier localStorage\n - DevTools > Application > Local Storage\n - Chercher les clรฉs: 'auth_token', 'access_token', 'crm-token', 'token'\n - Au moins une clรฉ doit exister\n\n# 4. Vรฉrifier les logs backend\n - Dans le terminal backend, chercher les erreurs 401\n```\n\n---\n\n## โŒ Erreur: \"Clรฉ invalide\" ou \"Erreur lors du test\"\n\n### Cause:\nLa clรฉ API est incorrecte ou l'API du provider est inaccessible.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier la clรฉ API\n - Copier la clรฉ exacte depuis votre compte Deepseek\n - Vรฉrifier qu'il n'y a pas d'espaces avant/aprรจs\n - Vรฉrifier qu'il n'y a pas de caractรจres spรฉciaux\n\n# 2. Tester la clรฉ manuellement\n curl -X GET \"https://api.deepseek.com/v1/models\" \\\n -H \"Authorization: Bearer sk-your-key-here\"\n\n Si vous recevez 401: La clรฉ est invalide\n Si vous recevez 200: La clรฉ est valide\n\n# 3. Vรฉrifier la connectivitรฉ rรฉseau\n - Vรฉrifier que vous avez accรจs ร  api.deepseek.com\n - Vรฉrifier si un firewall/proxy bloque les connexions\n\n# 4. Vรฉrifier les logs backend\n - Chercher des erreurs ECONNREFUSED\n - Chercher des erreurs 401/403\n```\n\n---\n\n## โŒ Erreur: \"Le modรจle ne s'affiche pas\"\n\n### Cause:\nLa validation a rรฉussi mais les modรจles ne sont pas retournรฉs.\n\n### Solutions:\n```bash\n# 1. Forcer un rechargement\n - Appuyer sur Ctrl+F5 (vidage du cache)\n\n# 2. Vรฉrifier la rรฉponse du backend\n - DevTools > Network > validate (request)\n - Chercher le champ \"models\" dans la rรฉponse\n\n Rรฉponse attendue:\n {\n \"valid\": true,\n \"provider\": \"deepseek\",\n \"models\": [\"deepseek-chat\", \"deepseek-coder\"]\n }\n\n# 3. Vรฉrifier les ร‰tats React\n - Ajouter des console.log dans handleTestApiKey()\n - Vรฉrifier que setAvailableModelsPerKey() est appelรฉ\n```\n\n---\n\n## โŒ Erreur: \"La clรฉ n'est pas sauvegardรฉe\"\n\n### Cause:\nLa sauvegarde a รฉchouรฉ cรดtรฉ backend ou base de donnรฉes.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier les logs backend\n - Chercher les erreurs Prisma\n - Chercher les erreurs de base de donnรฉes\n\n# 2. Vรฉrifier la requรชte PUT\n - DevTools > Network > /user (PUT request)\n - Vรฉrifier que le body contient tous les champs\n\n Body attendu:\n {\n \"deepseekApiKey\": \"sk-xxxx\",\n \"defaultProvider\": \"deepseek\",\n \"defaultModel\": \"deepseek-chat\"\n }\n\n# 3. Vรฉrifier la rรฉponse\n - La rรฉponse doit contenir: { \"success\": true }\n\n# 4. Vรฉrifier la base de donnรฉes\n - Vรฉrifier que la table ai_settings existe\n - Vรฉrifier que les colonnes deepseekApiKey existent\n - Vรฉrifier que le userId est correct\n```\n\n---\n\n## โŒ Erreur: \"Aprรจs rechargement, la clรฉ a disparu\"\n\n### Cause:\nLa clรฉ n'a pas รฉtรฉ sauvegardรฉe en base de donnรฉes, ou le rechargement ne rรฉcupรจre pas correctement les donnรฉes.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier le chargement au dรฉmarrage\n - DevTools > Network > /user/full (GET request)\n - Vรฉrifier que la rรฉponse contient deepseekApiKey\n\n Rรฉponse attendue:\n {\n \"deepseekApiKey\": \"sk-xxxx\",\n \"defaultProvider\": \"deepseek\",\n \"defaultModel\": \"deepseek-chat\"\n }\n\n# 2. Vรฉrifier les logs de loadApiKeys()\n - Ajouter des console.log\n - Vรฉrifier le statut HTTP de la rรฉponse\n\n# 3. Tester directement l'API\n curl -H \"Authorization: Bearer $TOKEN\" \\\n http://localhost:3001/api/ai-billing/api-keys/user/full\n\n# 4. Vรฉrifier la base de donnรฉes\n - SELECT * FROM ai_settings WHERE userId = 'xxx';\n - Vรฉrifier que deepseekApiKey contient la clรฉ\n\n# 5. Vรฉrifier le setState\n - Le state llmKeys doit รชtre rempli aprรจs loadApiKeys()\n```\n\n---\n\n## โŒ Erreur: \"Le backend ne dรฉmarre pas\"\n\n### Cause:\nErreurs de dรฉpendances ou de configuration.\n\n### Solutions:\n```bash\n# 1. Installer les dรฉpendances\n cd backend\n npm install\n\n# 2. Vรฉrifier les variables d'environnement\n - Copier .env.example en .env\n - Remplir les valeurs nรฉcessaires\n\n# 3. Vรฉrifier la base de donnรฉes\n - Vรฉrifier que PostgreSQL/MongoDB est lancรฉ\n - Vรฉrifier que la connexion DB est correcte dans .env\n\n# 4. Exรฉcuter les migrations\n npm run migrate\n ou\n npm run prisma:migrate\n\n# 5. Lancer le backend\n npm run dev\n\n# 6. Vรฉrifier que le port 3001 n'est pas utilisรฉ\n lsof -i :3001 # macOS/Linux\n netstat -ano | findstr :3001 # Windows\n```\n\n---\n\n## โŒ Erreur: \"Le frontend ne dรฉmarre pas\"\n\n### Cause:\nErreurs de compilation ou dรฉpendances manquantes.\n\n### Solutions:\n```bash\n# 1. Installer les dรฉpendances\n cd frontend\n npm install\n\n# 2. Supprimer le cache\n rm -rf .next node_modules\n npm install\n\n# 3. Compiler\n npm run build\n\n# 4. Lancer le frontend\n npm run dev\n\n# 5. Vรฉrifier que le port 3000 n'est pas utilisรฉ\n lsof -i :3000 # macOS/Linux\n netstat -ano | findstr :3000 # Windows\n```\n\n---\n\n## ๐Ÿงช Tests ne fonctionnent pas\n\n### Curl:\n\n```bash\n# Vรฉrifier que curl est installรฉ\nwhich curl\n\n# Vรฉrifier que le backend rรฉpond\ncurl -I http://localhost:3001/health\n\n# Tester l'authentification\ncurl -X POST http://localhost:3001/api/auth/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"test@example.com\",\"password\":\"test\"}'\n```\n\n### Playwright:\n\n```bash\n# Installer les navigateurs\nnpx playwright install\n\n# Vรฉrifier la version\nnpx playwright --version\n\n# Vรฉrifier que le frontend rรฉpond\ncurl -I http://localhost:3000\n\n# Lancer les tests avec debug\nnpx playwright test tests/api-keys-deepseek.spec.ts --debug\n\n# Lancer avec logs\nnpx playwright test tests/api-keys-deepseek.spec.ts --debug --headed\n```\n\n---\n\n## ๐Ÿ“‹ Checklist de Diagnostic\n\n- [ ] Backend dรฉmarre sans erreurs\n- [ ] Frontend dรฉmarre sans erreurs\n- [ ] Accรจs ร  http://localhost:3000\n- [ ] Accรจs ร  http://localhost:3001\n- [ ] Authentification fonctionne\n- [ ] Token dans localStorage\n- [ ] Page /settings/ai-api-keys accessible\n- [ ] Onglet \"LLM\" visible\n- [ ] Dropdown \"Provider\" fonctionnel\n- [ ] Input \"Clรฉ\" รฉditable\n- [ ] Bouton \"Tester\" cliquable\n- [ ] Toast notification affichรฉes\n- [ ] Base de donnรฉes accessible\n- [ ] Clรฉs sauvegardรฉes en BD\n- [ ] Page recharge correctement\n\n---\n\n## ๐Ÿ†˜ Aide Supplรฉmentaire\n\n**Si vous toujours des problรจmes:**\n\n1. **Vรฉrifier les logs**:\n ```bash\n npm run dev -- --debug\n ```\n\n2. **Vรฉrifier la console navigateur**:\n - DevTools (F12)\n - Console tab\n - Chercher les erreurs\n\n3. **Vรฉrifier les requรชtes rรฉseau**:\n - DevTools (F12)\n - Network tab\n - Chercher les rรฉponses 401/403/500\n\n4. **Nettoyer complรจtement**:\n ```bash\n # Backend\n cd backend\n rm -rf node_modules dist .env\n npm install\n\n # Frontend\n cd frontend\n rm -rf node_modules .next .env\n npm install\n ```\n\n5. **Rรฉinitialiser les donnรฉes**:\n ```bash\n # Base de donnรฉes\n # Supprimer et recrรฉer\n npm run prisma:reset\n ```\n\n---\n\n**Derniรจre ressource**: Consulter les fichiers de configuration\n- `backend/.env`\n- `frontend/.env.local`\n- `package.json`\n\n---\n\n**Date**: 19 Janvier 2026\n**Status**: โœ… Guide Complet\n"}, "379c58a4218ef191073dd887ca466f12266e63c5": {"t": 1785765435.0564017, "n": 7200, "h": "1bcff09cb22419b2", "c": "# ๐Ÿ”ง Troubleshooting - Clรฉs API Deepseek\n\n## โŒ Erreur: \"Authentification requise. Veuillez vous connecter.\"\n\n### Cause:\nLe token n'est pas trouvรฉ dans localStorage.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier que vous รชtes connectรฉ\n - Vรฉrifiez que vous avez entrรฉ vos identifiants de connexion\n - Vรฉrifiez que la session n'a pas expirรฉ\n\n# 2. Nettoyer le cache navigateur\n - DevTools > Application > Clear Site Data\n - Fermer et rouvrir le navigateur\n\n# 3. Vรฉrifier localStorage\n - DevTools > Application > Local Storage\n - Chercher les clรฉs: 'auth_token', 'access_token', 'crm-token', 'token'\n - Au moins une clรฉ doit exister\n\n# 4. Vรฉrifier les logs backend\n - Dans le terminal backend, chercher les erreurs 401\n```\n\n---\n\n## โŒ Erreur: \"Clรฉ invalide\" ou \"Erreur lors du test\"\n\n### Cause:\nLa clรฉ API est incorrecte ou l'API du provider est inaccessible.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier la clรฉ API\n - Copier la clรฉ exacte depuis votre compte Deepseek\n - Vรฉrifier qu'il n'y a pas d'espaces avant/aprรจs\n - Vรฉrifier qu'il n'y a pas de caractรจres spรฉciaux\n\n# 2. Tester la clรฉ manuellement\n curl -X GET \"https://api.deepseek.com/v1/models\" \\\n -H \"Authorization: Bearer sk-your-key-here\"\n\n Si vous recevez 401: La clรฉ est invalide\n Si vous recevez 200: La clรฉ est valide\n\n# 3. Vรฉrifier la connectivitรฉ rรฉseau\n - Vรฉrifier que vous avez accรจs ร  api.deepseek.com\n - Vรฉrifier si un firewall/proxy bloque les connexions\n\n# 4. Vรฉrifier les logs backend\n - Chercher des erreurs ECONNREFUSED\n - Chercher des erreurs 401/403\n```\n\n---\n\n## โŒ Erreur: \"Le modรจle ne s'affiche pas\"\n\n### Cause:\nLa validation a rรฉussi mais les modรจles ne sont pas retournรฉs.\n\n### Solutions:\n```bash\n# 1. Forcer un rechargement\n - Appuyer sur Ctrl+F5 (vidage du cache)\n\n# 2. Vรฉrifier la rรฉponse du backend\n - DevTools > Network > validate (request)\n - Chercher le champ \"models\" dans la rรฉponse\n\n Rรฉponse attendue:\n {\n \"valid\": true,\n \"provider\": \"deepseek\",\n \"models\": [\"deepseek-chat\", \"deepseek-coder\"]\n }\n\n# 3. Vรฉrifier les ร‰tats React\n - Ajouter des console.log dans handleTestApiKey()\n - Vรฉrifier que setAvailableModelsPerKey() est appelรฉ\n```\n\n---\n\n## โŒ Erreur: \"La clรฉ n'est pas sauvegardรฉe\"\n\n### Cause:\nLa sauvegarde a รฉchouรฉ cรดtรฉ backend ou base de donnรฉes.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier les logs backend\n - Chercher les erreurs Prisma\n - Chercher les erreurs de base de donnรฉes\n\n# 2. Vรฉrifier la requรชte PUT\n - DevTools > Network > /user (PUT request)\n - Vรฉrifier que le body contient tous les champs\n\n Body attendu:\n {\n \"deepseekApiKey\": \"sk-xxxx\",\n \"defaultProvider\": \"deepseek\",\n \"defaultModel\": \"deepseek-chat\"\n }\n\n# 3. Vรฉrifier la rรฉponse\n - La rรฉponse doit contenir: { \"success\": true }\n\n# 4. Vรฉrifier la base de donnรฉes\n - Vรฉrifier que la table ai_settings existe\n - Vรฉrifier que les colonnes deepseekApiKey existent\n - Vรฉrifier que le userId est correct\n```\n\n---\n\n## โŒ Erreur: \"Aprรจs rechargement, la clรฉ a disparu\"\n\n### Cause:\nLa clรฉ n'a pas รฉtรฉ sauvegardรฉe en base de donnรฉes, ou le rechargement ne rรฉcupรจre pas correctement les donnรฉes.\n\n### Solutions:\n```bash\n# 1. Vรฉrifier le chargement au dรฉmarrage\n - DevTools > Network > /user/full (GET request)\n - Vรฉrifier que la rรฉponse contient deepseekApiKey\n\n Rรฉponse attendue:\n {\n \"deepseekApiKey\": \"sk-xxxx\",\n \"defaultProvider\": \"deepseek\",\n \"defaultModel\": \"deepseek-chat\"\n }\n\n# 2. Vรฉrifier les logs de loadApiKeys()\n - Ajouter des console.log\n - Vรฉrifier le statut HTTP de la rรฉponse\n\n# 3. Tester directement l'API\n curl -H \"Authorization: Bearer $TOKEN\" \\\n http://localhost:3001/api/ai-billing/api-keys/user/full\n\n# 4. Vรฉrifier la base de donnรฉes\n - SELECT * FROM ai_settings WHERE userId = 'xxx';\n - Vรฉrifier que deepseekApiKey contient la clรฉ\n\n# 5. Vรฉrifier le setState\n - Le state llmKeys doit รชtre rempli aprรจs loadApiKeys()\n```\n\n---\n\n## โŒ Erreur: \"Le backend ne dรฉmarre pas\"\n\n### Cause:\nErreurs de dรฉpendances ou de configuration.\n\n### Solutions:\n```bash\n# 1. Installer les dรฉpendances\n cd backend\n npm install\n\n# 2. Vรฉrifier les variables d'environnement\n - Copier .env.example en .env\n - Remplir les valeurs nรฉcessaires\n\n# 3. Vรฉrifier la base de donnรฉes\n - Vรฉrifier que PostgreSQL/MongoDB est lancรฉ\n - Vรฉrifier que la connexion DB est correcte dans .env\n\n# 4. Exรฉcuter les migrations\n npm run migrate\n ou\n npm run prisma:migrate\n\n# 5. Lancer le backend\n npm run dev\n\n# 6. Vรฉrifier que le port 3001 n'est pas utilisรฉ\n lsof -i :3001 # macOS/Linux\n netstat -ano | findstr :3001 # Windows\n```\n\n---\n\n## โŒ Erreur: \"Le frontend ne dรฉmarre pas\"\n\n### Cause:\nErreurs de compilation ou dรฉpendances manquantes.\n\n### Solutions:\n```bash\n# 1. Installer les dรฉpendances\n cd frontend\n npm install\n\n# 2. Supprimer le cache\n rm -rf .next node_modules\n npm install\n\n# 3. Compiler\n npm run build\n\n# 4. Lancer le frontend\n npm run dev\n\n# 5. Vรฉrifier que le port 3000 n'est pas utilisรฉ\n lsof -i :3000 # macOS/Linux\n netstat -ano | findstr :3000 # Windows\n```\n\n---\n\n## ๐Ÿงช Tests ne fonctionnent pas\n\n### Curl:\n\n```bash\n# Vรฉrifier que curl est installรฉ\nwhich curl\n\n# Vรฉrifier que le backend rรฉpond\ncurl -I http://localhost:3001/health\n\n# Tester l'authentification\ncurl -X POST http://localhost:3001/api/auth/login \\\n -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"test@example.com\",\"password\":\"test\"}'\n```\n\n### Playwright:\n\n```bash\n# Installer les navigateurs\nnpx playwright install\n\n# Vรฉrifier la version\nnpx playwright --version\n\n# Vรฉrifier que le frontend rรฉpond\ncurl -I http://localhost:3000\n\n# Lancer les tests avec debug\nnpx playwright test tests/api-keys-deepseek.spec.ts --debug\n\n# Lancer avec logs\nnpx playwright test tests/api-keys-deepseek.spec.ts --debug --headed\n```\n\n---\n\n## ๐Ÿ“‹ Checklist de Diagnostic\n\n- [ ] Backend dรฉmarre sans erreurs\n- [ ] Frontend dรฉmarre sans erreurs\n- [ ] Accรจs ร  http://localhost:3000\n- [ ] Accรจs ร  http://localhost:3001\n- [ ] Authentification fonctionne\n- [ ] Token dans localStorage\n- [ ] Page /settings/ai-api-keys accessible\n- [ ] Onglet \"LLM\" visible\n- [ ] Dropdown \"Provider\" fonctionnel\n- [ ] Input \"Clรฉ\" รฉditable\n- [ ] Bouton \"Tester\" cliquable\n- [ ] Toast notification affichรฉes\n- [ ] Base de donnรฉes accessible\n- [ ] Clรฉs sauvegardรฉes en BD\n- [ ] Page recharge correctement\n\n---\n\n## ๐Ÿ†˜ Aide Supplรฉmentaire\n\n**Si vous toujours des problรจmes:**\n\n1. **Vรฉrifier les logs**:\n ```bash\n npm run dev -- --debug\n ```\n\n2. **Vรฉrifier la console navigateur**:\n - DevTools (F12)\n - Console tab\n - Chercher les erreurs\n\n3. **Vรฉrifier les requรชtes rรฉseau**:\n - DevTools (F12)\n - Network tab\n - Chercher les rรฉponses 401/403/500\n\n4. **Nettoyer complรจtement**:\n ```bash\n # Backend\n cd backend\n rm -rf node_modules dist .env\n npm install\n\n # Frontend\n cd frontend\n rm -rf node_modules .next .env\n npm install\n ```\n\n5. **Rรฉinitialiser les donnรฉes**:\n ```bash\n # Base de donnรฉes\n # Supprimer et recrรฉer\n npm run prisma:reset\n ```\n\n---\n\n**Derniรจre ressource**: Consulter les fichiers de configuration\n- `backend/.env`\n- `frontend/.env.local`\n- `package.json`\n\n---\n\n**Date**: 19 Janvier 2026\n**Status**: โœ… Guide Complet\n"}}}}