Files

1 line
73 KiB
JSON

{"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"}}}}