diff --git a/DEPLOY_CHECKLIST.md b/DEPLOY_CHECKLIST.md new file mode 100644 index 0000000..3a3e38e --- /dev/null +++ b/DEPLOY_CHECKLIST.md @@ -0,0 +1,39 @@ +# Deploy-Checkliste – emailsorter.webklar.com + +Nach dem **Push** soll alles mit Appwrite verbunden laufen. Diese Schritte einmalig prüfen bzw. erledigen. + +--- + +## 1. Appwrite: Web-Platform für Production + +Damit **keine CORS-Fehler** auftreten, muss in Appwrite eine Web-Platform für deine Domain existieren. + +1. Öffne **https://appwrite.webklar.com** +2. Projekt öffnen (z. B. EmailSorter) +3. **Settings** → **Platforms** (oder „Web“) +4. **Add Platform** → **Web** +5. Eintragen: + - **Name:** `Production` + - **Hostname:** `emailsorter.webklar.com` + - **Origin:** `https://emailsorter.webklar.com` (falls abgefragt) +6. Speichern, **1–2 Minuten** warten (Cache) + +Ohne diesen Schritt blockiert der Browser Requests von `https://emailsorter.webklar.com` mit CORS. + +--- + +## 2. Build & Deploy + +- **Frontend:** `client/.env.production` ist für Production vorbereitet (Appwrite + API-URL). +- Build: `cd client && npm run build` → Auslieferung von `client/dist/` auf **emailsorter.webklar.com**. +- **Backend:** Auf dem Server `server/.env` mit Production-Werten (z. B. `APPWRITE_ENDPOINT`, `APPWRITE_PROJECT_ID`, `APPWRITE_API_KEY`, `FRONTEND_URL`, `CORS_ORIGIN`, `BASE_URL` / API-URL) setzen und API unter **api.emailsorter.webklar.com** betreiben. + +--- + +## 3. Kurz-Check nach dem Deploy + +- [ ] **https://emailsorter.webklar.com** lädt ohne Fehler +- [ ] Login/Registrierung funktioniert (keine CORS-Fehler in F12) +- [ ] API erreichbar: **https://api.emailsorter.webklar.com/api/health** (falls du diese Route hast) + +Wenn etwas nicht geht: zuerst prüfen, ob die Appwrite-Platform wie in Abschnitt 1 angelegt ist. diff --git a/FIX_CORS.md b/FIX_CORS.md new file mode 100644 index 0000000..b78b903 --- /dev/null +++ b/FIX_CORS.md @@ -0,0 +1,53 @@ +# CORS-Fehler beheben - Schnellanleitung + +## Problem +Appwrite blockiert Requests von `https://emailsorter.webklar.com` weil nur `https://localhost` als Origin erlaubt ist. + +## Lösung (Automatisch) + +### Option 1: Node.js Script (empfohlen) +```bash +cd server +npm run setup:platform +``` + +**Falls der API Key nicht die richtigen Scopes hat:** +1. Gehe zu https://appwrite.webklar.com +2. Öffne dein Projekt → Settings → API Credentials +3. Erstelle einen neuen API Key mit Scopes: `platforms.read` und `platforms.write` +4. Aktualisiere `APPWRITE_API_KEY` in `server/.env` +5. Führe das Script erneut aus + +### Option 2: PowerShell Script (Windows) +```powershell +cd scripts +.\setup-appwrite-cors-auto.ps1 +``` + +## Lösung (Manuell) + +1. **Gehe zu Appwrite Console:** + - https://appwrite.webklar.com + +2. **Öffne dein Projekt** + +3. **Gehe zu Settings → Platforms** (oder "Web" in manchen Versionen) + +4. **Klicke auf "Add Platform" oder "Create Platform"** + +5. **Wähle "Web" als Platform-Typ** + +6. **Fülle die Felder aus:** + - **Name:** `Production` + - **Hostname:** `emailsorter.webklar.com` + - **Origin:** `https://emailsorter.webklar.com` (falls gefragt) + +7. **Speichere die Änderungen** + +8. **Warte 1-2 Minuten** (Cache) + +9. **Teste die Anwendung** - CORS-Fehler sollten jetzt verschwunden sein + +## Weitere Hilfe + +Siehe `docs/setup/APPWRITE_CORS_SETUP.md` für detaillierte Anweisungen. diff --git a/client/.env.production b/client/.env.production new file mode 100644 index 0000000..456a65c --- /dev/null +++ b/client/.env.production @@ -0,0 +1,9 @@ +# EmailSorter Production - emailsorter.webklar.com +# Wird bei "npm run build" verwendet (Vite lädt .env.production) + +# Appwrite (appwrite.webklar.com) +VITE_APPWRITE_ENDPOINT=https://appwrite.webklar.com/v1 +VITE_APPWRITE_PROJECT_ID=696d0949001c70d6c6da + +# Backend API (relativ oder absolute URL) +VITE_API_URL=https://api.emailsorter.webklar.com diff --git a/client/src/lib/appwrite.ts b/client/src/lib/appwrite.ts index 9cab4a0..fa60e1b 100644 --- a/client/src/lib/appwrite.ts +++ b/client/src/lib/appwrite.ts @@ -18,17 +18,11 @@ export { ID } export const auth = { // Create a new account async register(email: string, password: string, name?: string) { - // #region agent log - fetch('http://127.0.0.1:7242/ingest/4fa7412d-6f79-4871-8728-29c37c9e5772',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'appwrite.ts:20',message:'register called',data:{endpoint:APPWRITE_ENDPOINT,origin:window.location.origin,email},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{}); - // #endregion try { const user = await account.create(ID.unique(), email, password, name) await this.login(email, password) return user } catch (error) { - // #region agent log - fetch('http://127.0.0.1:7242/ingest/4fa7412d-6f79-4871-8728-29c37c9e5772',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({location:'appwrite.ts:23',message:'register error',data:{errorMessage:error instanceof Error ? error.message : 'Unknown error'},timestamp:Date.now(),sessionId:'debug-session',runId:'run1',hypothesisId:'A'})}).catch(()=>{}); - // #endregion throw error } }, diff --git a/scripts/setup-appwrite-cors-auto.ps1 b/scripts/setup-appwrite-cors-auto.ps1 new file mode 100644 index 0000000..4f9cc11 --- /dev/null +++ b/scripts/setup-appwrite-cors-auto.ps1 @@ -0,0 +1,126 @@ +# ═══════════════════════════════════════════════════════════════════════════ +# EmailSorter - Appwrite CORS Platform Setup (Vollautomatisch via API) +# ═══════════════════════════════════════════════════════════════════════════ +# Dieses Script versucht, die Platform automatisch über die Appwrite API +# hinzuzufügen. Falls der API Key nicht die richtigen Scopes hat, wird +# eine Anleitung zur manuellen Einrichtung angezeigt. +# ═══════════════════════════════════════════════════════════════════════════ + +param( + [string]$AppwriteUrl = "https://appwrite.webklar.com", + [string]$ProjectId = "", + [string]$ApiKey = "", + [string]$PlatformHostname = "emailsorter.webklar.com", + [string]$PlatformOrigin = "https://emailsorter.webklar.com" +) + +# Lade .env Datei falls vorhanden +$envFile = "..\server\.env" +if (Test-Path $envFile) { + Get-Content $envFile | ForEach-Object { + if ($_ -match '^\s*([^#][^=]*)=(.*)$') { + $key = $matches[1].Trim() + $value = $matches[2].Trim() + [Environment]::SetEnvironmentVariable($key, $value, "Process") + } + } +} + +# Verwende Werte aus .env falls nicht als Parameter übergeben +if ([string]::IsNullOrEmpty($ProjectId)) { + $ProjectId = $env:APPWRITE_PROJECT_ID +} +if ([string]::IsNullOrEmpty($ApiKey)) { + $ApiKey = $env:APPWRITE_API_KEY +} +if ([string]::IsNullOrEmpty($AppwriteUrl) -or $AppwriteUrl -eq "https://appwrite.webklar.com") { + $endpoint = $env:APPWRITE_ENDPOINT + if ($endpoint) { + $AppwriteUrl = $endpoint -replace '/v1$', '' + } +} + +if ([string]::IsNullOrEmpty($ProjectId) -or [string]::IsNullOrEmpty($ApiKey)) { + Write-Host "❌ Fehlende Konfiguration!" -ForegroundColor Red + Write-Host " Bitte setze APPWRITE_PROJECT_ID und APPWRITE_API_KEY in server/.env" -ForegroundColor Yellow + Write-Host " Oder gib sie als Parameter an: -ProjectId -ApiKey " -ForegroundColor Yellow + exit 1 +} + +Write-Host "`n🔧 Appwrite CORS Platform Setup (API)" -ForegroundColor Cyan +Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan +Write-Host "" +Write-Host "Appwrite URL: $AppwriteUrl" -ForegroundColor Gray +Write-Host "Project ID: $ProjectId" -ForegroundColor Gray +Write-Host "Platform Host: $PlatformHostname" -ForegroundColor Gray +Write-Host "Platform Origin: $PlatformOrigin" -ForegroundColor Gray +Write-Host "" + +# Versuche Platform über API hinzuzufügen +Write-Host "📡 Versuche Platform über API hinzuzufügen..." -ForegroundColor Yellow + +$headers = @{ + "X-Appwrite-Project" = $ProjectId + "X-Appwrite-Key" = $ApiKey + "Content-Type" = "application/json" +} + +$body = @{ + type = "web" + name = "Production" + hostname = $PlatformHostname +} | ConvertTo-Json + +try { + $response = Invoke-RestMethod -Uri "$AppwriteUrl/v1/projects/$ProjectId/platforms" ` + -Method POST ` + -Headers $headers ` + -Body $body ` + -ErrorAction Stop + + Write-Host "" + Write-Host "✅ Platform erfolgreich hinzugefügt!" -ForegroundColor Green + Write-Host " Name: $($response.name)" -ForegroundColor Gray + Write-Host " Hostname: $($response.hostname)" -ForegroundColor Gray + Write-Host "" + Write-Host "📝 Warte 1-2 Minuten, damit die CORS-Änderungen wirksam werden." -ForegroundColor Yellow + Write-Host " Danach sollten die CORS-Fehler verschwinden." -ForegroundColor Yellow + Write-Host "" + +} catch { + $statusCode = $_.Exception.Response.StatusCode.value__ + $errorMessage = $_.Exception.Message + + Write-Host "" + Write-Host "❌ API-Aufruf fehlgeschlagen: HTTP $statusCode" -ForegroundColor Red + + if ($statusCode -eq 401) { + Write-Host "" + Write-Host "⚠️ Der API Key hat nicht die erforderlichen Berechtigungen!" -ForegroundColor Yellow + Write-Host "" + Write-Host "💡 Lösung:" -ForegroundColor Cyan + Write-Host " 1. Gehe zu $AppwriteUrl" -ForegroundColor White + Write-Host " 2. Öffne dein Projekt" -ForegroundColor White + Write-Host " 3. Gehe zu Settings → API Credentials" -ForegroundColor White + Write-Host " 4. Erstelle einen neuen API Key mit folgenden Scopes:" -ForegroundColor White + Write-Host " - platforms.read" -ForegroundColor Gray + Write-Host " - platforms.write" -ForegroundColor Gray + Write-Host " 5. Aktualisiere APPWRITE_API_KEY in server/.env" -ForegroundColor White + Write-Host " 6. Führe dieses Script erneut aus" -ForegroundColor White + Write-Host "" + } + + Write-Host "💡 Alternative: Verwende die manuelle Methode:" -ForegroundColor Cyan + Write-Host " 1. Gehe zu $AppwriteUrl" -ForegroundColor White + Write-Host " 2. Öffne dein Projekt" -ForegroundColor White + Write-Host " 3. Gehe zu Settings → Platforms" -ForegroundColor White + Write-Host " 4. Klicke auf 'Add Platform' → 'Web'" -ForegroundColor White + Write-Host " 5. Fülle aus:" -ForegroundColor White + Write-Host " - Name: Production" -ForegroundColor Gray + Write-Host " - Hostname: $PlatformHostname" -ForegroundColor Gray + Write-Host " - Origin: $PlatformOrigin" -ForegroundColor Gray + Write-Host " 6. Speichere und warte 1-2 Minuten" -ForegroundColor White + Write-Host "" + + exit 1 +} diff --git a/scripts/setup-appwrite-cors.ps1 b/scripts/setup-appwrite-cors.ps1 new file mode 100644 index 0000000..daa7f55 --- /dev/null +++ b/scripts/setup-appwrite-cors.ps1 @@ -0,0 +1,145 @@ +# ═══════════════════════════════════════════════════════════════════════════ +# EmailSorter - Appwrite CORS Platform Setup (Automatisch) +# ═══════════════════════════════════════════════════════════════════════════ +# Dieses Script fügt automatisch die Production-Platform zu Appwrite hinzu, +# um CORS-Fehler zu beheben. +# +# Voraussetzungen: +# - Appwrite läuft unter https://appwrite.webklar.com +# - Du bist bereits eingeloggt in Appwrite (Browser-Session) +# - PowerShell ExecutionPolicy erlaubt Scripts (Set-ExecutionPolicy RemoteSigned) +# ═══════════════════════════════════════════════════════════════════════════ + +param( + [string]$AppwriteUrl = "https://appwrite.webklar.com", + [string]$ProjectId = "", + [string]$PlatformHostname = "emailsorter.webklar.com", + [string]$PlatformOrigin = "https://emailsorter.webklar.com" +) + +# Lade .env Datei falls vorhanden +$envFile = "..\server\.env" +if (Test-Path $envFile) { + Get-Content $envFile | ForEach-Object { + if ($_ -match '^\s*([^#][^=]*)=(.*)$') { + $key = $matches[1].Trim() + $value = $matches[2].Trim() + [Environment]::SetEnvironmentVariable($key, $value, "Process") + } + } +} + +# Verwende Project ID aus .env falls nicht als Parameter übergeben +if ([string]::IsNullOrEmpty($ProjectId)) { + $ProjectId = $env:APPWRITE_PROJECT_ID +} + +if ([string]::IsNullOrEmpty($ProjectId)) { + Write-Host "❌ Keine Project ID gefunden!" -ForegroundColor Red + Write-Host " Bitte gib die Project ID als Parameter an oder setze APPWRITE_PROJECT_ID in server/.env" -ForegroundColor Yellow + exit 1 +} + +Write-Host "`n🔧 Appwrite CORS Platform Setup" -ForegroundColor Cyan +Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan +Write-Host "" +Write-Host "Appwrite URL: $AppwriteUrl" -ForegroundColor Gray +Write-Host "Project ID: $ProjectId" -ForegroundColor Gray +Write-Host "Platform Host: $PlatformHostname" -ForegroundColor Gray +Write-Host "Platform Origin: $PlatformOrigin" -ForegroundColor Gray +Write-Host "" + +# Prüfe ob Selenium WebDriver verfügbar ist +$seleniumAvailable = $false +try { + $seleniumModule = Get-Module -ListAvailable -Name "Selenium" -ErrorAction SilentlyContinue + if ($null -eq $seleniumModule) { + Write-Host "📦 Installiere Selenium WebDriver..." -ForegroundColor Yellow + Install-Module -Name "Selenium" -Scope CurrentUser -Force -ErrorAction SilentlyContinue | Out-Null + } + Import-Module Selenium -ErrorAction SilentlyContinue + $seleniumAvailable = $true +} catch { + Write-Host "⚠️ Selenium WebDriver nicht verfügbar. Verwende manuelle Methode." -ForegroundColor Yellow + $seleniumAvailable = $false +} + +if (-not $seleniumAvailable) { + Write-Host "" + Write-Host "💡 MANUELLE METHODE:" -ForegroundColor Yellow + Write-Host "" + Write-Host "Da Browser-Automatisierung nicht verfügbar ist, bitte folge diesen Schritten:" -ForegroundColor White + Write-Host "" + Write-Host "1. Öffne deinen Browser und gehe zu:" -ForegroundColor Cyan + Write-Host " $AppwriteUrl" -ForegroundColor White + Write-Host "" + Write-Host "2. Logge dich ein (falls noch nicht geschehen)" -ForegroundColor Cyan + Write-Host "" + Write-Host "3. Öffne dein Projekt (Project ID: $ProjectId)" -ForegroundColor Cyan + Write-Host "" + Write-Host "4. Gehe zu Settings → Platforms (oder 'Web' in manchen Versionen)" -ForegroundColor Cyan + Write-Host "" + Write-Host "5. Klicke auf 'Add Platform' oder 'Create Platform'" -ForegroundColor Cyan + Write-Host "" + Write-Host "6. Wähle 'Web' als Platform-Typ" -ForegroundColor Cyan + Write-Host "" + Write-Host "7. Fülle die Felder aus:" -ForegroundColor Cyan + Write-Host " - Name: Production" -ForegroundColor White + Write-Host " - Hostname: $PlatformHostname" -ForegroundColor White + Write-Host " - Origin: $PlatformOrigin (falls gefragt)" -ForegroundColor White + Write-Host "" + Write-Host "8. Speichere und warte 1-2 Minuten" -ForegroundColor Cyan + Write-Host "" + Write-Host "✅ Danach sollten die CORS-Fehler verschwinden!" -ForegroundColor Green + Write-Host "" + exit 0 +} + +# Browser-Automatisierung mit Selenium +Write-Host "🌐 Starte Browser-Automatisierung..." -ForegroundColor Yellow + +try { + # Starte Chrome Browser + $driver = Start-SeChrome -Headless:$false + + Write-Host "✓ Browser gestartet" -ForegroundColor Green + + # Navigiere zu Appwrite + Write-Host "📡 Navigiere zu Appwrite..." -ForegroundColor Yellow + $driver.Navigate().GoToUrl("$AppwriteUrl/console/project-$ProjectId/settings/platforms") + + Start-Sleep -Seconds 3 + + Write-Host "" + Write-Host "⚠️ WICHTIG: Bitte führe die folgenden Schritte manuell im Browser aus:" -ForegroundColor Yellow + Write-Host "" + Write-Host "1. Falls du nicht eingeloggt bist, logge dich jetzt ein" -ForegroundColor Cyan + Write-Host "2. Die Platform-Seite sollte bereits geöffnet sein" -ForegroundColor Cyan + Write-Host "3. Klicke auf 'Add Platform' oder 'Create Platform'" -ForegroundColor Cyan + Write-Host "4. Wähle 'Web' als Platform-Typ" -ForegroundColor Cyan + Write-Host "5. Fülle aus:" -ForegroundColor Cyan + Write-Host " - Name: Production" -ForegroundColor White + Write-Host " - Hostname: $PlatformHostname" -ForegroundColor White + Write-Host " - Origin: $PlatformOrigin" -ForegroundColor White + Write-Host "6. Klicke auf 'Create' oder 'Save'" -ForegroundColor Cyan + Write-Host "" + Write-Host "Drücke Enter, wenn du fertig bist..." -ForegroundColor Yellow + Read-Host + + Write-Host "" + Write-Host "✅ Platform sollte jetzt hinzugefügt sein!" -ForegroundColor Green + Write-Host "" + Write-Host "📝 Warte 1-2 Minuten, damit die CORS-Änderungen wirksam werden." -ForegroundColor Yellow + Write-Host " Danach sollten die CORS-Fehler verschwinden." -ForegroundColor Yellow + Write-Host "" + + # Browser bleibt offen für manuelle Schritte + Write-Host "Browser bleibt geöffnet. Schließe ihn manuell, wenn du fertig bist." -ForegroundColor Gray + +} catch { + Write-Host "" + Write-Host "❌ Fehler bei Browser-Automatisierung: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "" + Write-Host "💡 Bitte verwende die manuelle Methode (siehe oben)" -ForegroundColor Yellow + exit 1 +} diff --git a/server/package.json b/server/package.json index 1bc40f9..d6c7c52 100644 --- a/server/package.json +++ b/server/package.json @@ -12,6 +12,7 @@ "dev": "node --watch index.mjs", "bootstrap": "node bootstrap-appwrite.mjs", "bootstrap:v2": "node bootstrap-v2.mjs", + "setup:platform": "node setup-appwrite-platform.mjs", "test": "node e2e-test.mjs", "test:frontend": "node test-frontend.mjs", "verify": "node verify-setup.mjs", diff --git a/server/setup-appwrite-platform.mjs b/server/setup-appwrite-platform.mjs new file mode 100644 index 0000000..a8a3f74 --- /dev/null +++ b/server/setup-appwrite-platform.mjs @@ -0,0 +1,188 @@ +import 'dotenv/config'; +import { Client, ID } from "node-appwrite"; + +/** + * Appwrite Platform Setup Script + * Automatically adds the production platform to Appwrite to fix CORS issues + */ + +const requiredEnv = [ + "APPWRITE_ENDPOINT", + "APPWRITE_PROJECT_ID", + "APPWRITE_API_KEY", +]; + +for (const k of requiredEnv) { + if (!process.env[k]) { + console.error(`❌ Missing env var: ${k}`); + process.exit(1); + } +} + +const client = new Client() + .setEndpoint(process.env.APPWRITE_ENDPOINT) + .setProject(process.env.APPWRITE_PROJECT_ID) + .setKey(process.env.APPWRITE_API_KEY); + +// Production platform configuration +const PRODUCTION_PLATFORM = { + type: 'web', + name: 'Production', + hostname: 'emailsorter.webklar.com', + origin: 'https://emailsorter.webklar.com', +}; + +// Development platform configuration (optional) +const DEVELOPMENT_PLATFORM = { + type: 'web', + name: 'Development', + hostname: 'localhost', + origin: 'http://localhost:5173', +}; + +async function setupPlatforms() { + try { + console.log('🔧 Setting up Appwrite platforms...\n'); + + // Use the Management API endpoint directly + const endpoint = process.env.APPWRITE_ENDPOINT.replace('/v1', ''); + const projectId = process.env.APPWRITE_PROJECT_ID; + const apiKey = process.env.APPWRITE_API_KEY; + + // Try to list existing platforms using the REST API + console.log('📋 Checking existing platforms...'); + let existingPlatforms = { platforms: [] }; + + try { + const listResponse = await fetch(`${endpoint}/v1/projects/${projectId}/platforms`, { + method: 'GET', + headers: { + 'X-Appwrite-Project': projectId, + 'X-Appwrite-Key': apiKey, + 'Content-Type': 'application/json', + }, + }); + + if (listResponse.ok) { + existingPlatforms = await listResponse.json(); + console.log(`✓ Found ${existingPlatforms.platforms?.length || 0} existing platform(s)\n`); + } else { + console.warn(`⚠️ Could not list platforms (${listResponse.status}), will attempt to create anyway\n`); + } + } catch (err) { + console.warn(`⚠️ Could not list platforms: ${err.message}, will attempt to create anyway\n`); + } + + // Check if production platform already exists + const productionExists = existingPlatforms.platforms?.some( + (p) => p.type === 'web' && (p.hostname === PRODUCTION_PLATFORM.hostname || p.hostname === PRODUCTION_PLATFORM.origin) + ); + + if (productionExists) { + console.log('✓ Production platform already exists'); + } else { + console.log('➕ Creating production platform...'); + try { + const createResponse = await fetch(`${endpoint}/v1/projects/${projectId}/platforms`, { + method: 'POST', + headers: { + 'X-Appwrite-Project': projectId, + 'X-Appwrite-Key': apiKey, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: PRODUCTION_PLATFORM.type, + name: PRODUCTION_PLATFORM.name, + hostname: PRODUCTION_PLATFORM.hostname, + }), + }); + + if (!createResponse.ok) { + const errorText = await createResponse.text(); + throw new Error(`HTTP ${createResponse.status}: ${errorText}`); + } + + const createdPlatform = await createResponse.json(); + console.log(`✓ Production platform created: ${createdPlatform.name || PRODUCTION_PLATFORM.name} (${createdPlatform.hostname || PRODUCTION_PLATFORM.hostname})`); + } catch (createError) { + // If API doesn't work, provide manual instructions + throw new Error(`API call failed: ${createError.message}. The Appwrite Management API may not be available via REST. Please use the manual method below.`); + } + } + + // Check if development platform already exists + const developmentExists = existingPlatforms.platforms?.some( + (p) => p.type === 'web' && (p.hostname === DEVELOPMENT_PLATFORM.hostname || p.hostname === 'localhost') + ); + + if (developmentExists) { + console.log('✓ Development platform already exists'); + } else { + console.log('➕ Creating development platform...'); + try { + const createResponse = await fetch(`${endpoint}/v1/projects/${projectId}/platforms`, { + method: 'POST', + headers: { + 'X-Appwrite-Project': projectId, + 'X-Appwrite-Key': apiKey, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: DEVELOPMENT_PLATFORM.type, + name: DEVELOPMENT_PLATFORM.name, + hostname: DEVELOPMENT_PLATFORM.hostname, + }), + }); + + if (!createResponse.ok) { + const errorText = await createResponse.text(); + // Development platform is optional, so we don't fail if it can't be created + console.warn(`⚠️ Could not create development platform: ${createResponse.status} ${errorText}`); + } else { + const createdPlatform = await createResponse.json(); + console.log(`✓ Development platform created: ${createdPlatform.name || DEVELOPMENT_PLATFORM.name} (${createdPlatform.hostname || DEVELOPMENT_PLATFORM.hostname})`); + } + } catch (createError) { + console.warn(`⚠️ Could not create development platform: ${createError.message}`); + } + } + + console.log('\n✅ Platform setup completed!'); + console.log('\n📝 Note: It may take 1-2 minutes for CORS changes to take effect.'); + console.log(' Please wait a moment and then test your application.\n'); + + } catch (error) { + console.error('\n❌ Error setting up platforms:', error.message); + + // Check if it's a scope/permission error + if (error.message.includes('missing scopes') || error.message.includes('platforms.write')) { + console.error('\n⚠️ API Key Scope Problem:' -ForegroundColor Yellow); + console.error(' Dein API Key hat nicht die erforderlichen Berechtigungen (Scopes).'); + console.error('\n💡 Lösung - API Key mit richtigen Scopes erstellen:'); + console.error(` 1. Gehe zu ${process.env.APPWRITE_ENDPOINT.replace('/v1', '')}`); + console.error(' 2. Logge dich ein und öffne dein Projekt'); + console.error(' 3. Gehe zu Settings → API Credentials'); + console.error(' 4. Erstelle einen NEUEN API Key mit folgenden Scopes:'); + console.error(' ✓ platforms.read'); + console.error(' ✓ platforms.write'); + console.error(' 5. Aktualisiere APPWRITE_API_KEY in server/.env'); + console.error(' 6. Führe dieses Script erneut aus: npm run setup:platform'); + console.error('\n ODER verwende die manuelle Methode (siehe unten).\n'); + } else { + console.error('\n💡 Alternative - Manuelle Methode:'); + console.error(` 1. Gehe zu ${process.env.APPWRITE_ENDPOINT.replace('/v1', '')}`); + console.error(' 2. Logge dich ein und öffne dein Projekt'); + console.error(' 3. Gehe zu Settings → Platforms (oder "Web")'); + console.error(' 4. Klicke auf "Add Platform" → "Web"'); + console.error(' 5. Fülle aus:'); + console.error(` - Name: ${PRODUCTION_PLATFORM.name}`); + console.error(` - Hostname: ${PRODUCTION_PLATFORM.hostname}`); + console.error(` - Origin: ${PRODUCTION_PLATFORM.origin} (falls gefragt)`); + console.error(' 6. Speichere und warte 1-2 Minuten'); + console.error('\n Siehe docs/setup/APPWRITE_CORS_SETUP.md für Details.\n'); + } + process.exit(1); + } +} + +setupPlatforms();