From 3990a8a34eef8a163a27d9cd1c12102383db627e Mon Sep 17 00:00:00 2001 From: josiadmin Date: Mon, 26 Jan 2026 12:46:17 +0100 Subject: [PATCH] mod login signin design --- DEPLOYMENT.md | 359 ++++++++++++++++++++++------ Dockerfile | 8 +- deploy.sh | 2 +- docker-compose.yml | 6 +- lib/controller/edit_controller.dart | 4 + lib/pages/edit_view.dart | 4 +- lib/pages/login_view.dart | 2 +- lib/pages/signin_view.dart | 5 +- lib/widgets/my_login_widget.dart | 4 +- lib/widgets/my_signin_widget.dart | 4 +- 10 files changed, 305 insertions(+), 93 deletions(-) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 3950c75..4f89f96 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -1,68 +1,50 @@ -# Backend-Proxy Setup - Deployment Anleitung +# Proxy Server Deployment - Anleitung ## 📋 Übersicht -Diese Anleitung erklärt, wie Sie die Appwrite Function für Geocoding deployen, um CORS-Probleme zu vermeiden. +Diese Anleitung erklärt, wie Sie den Reverse Proxy Server für PTV API Geocoding deployen. Der Proxy umgeht CORS-Probleme und läuft als eigenständiger Container. -## 🚀 Deployment Schritte +## 🏗️ Architektur -### 1. Appwrite Console öffnen +``` +Browser (Flutter Web App) + ↓ +Proxy Server (localhost:3000 / your-server.com:3000) + ↓ +PTV Geocoding API (api.myptv.com) +``` -Navigieren Sie zu Ihrer Appwrite Console: -`https://appwrite.joshihomeserver.ipv64.net/console` +## 🚀 Lokale Entwicklung -### 2. Function erstellen +### 1. Proxy Server starten -1. Klicken Sie auf **Functions** im Menü -2. Klicken Sie auf **Create Function** -3. Füllen Sie die Details aus: - - **Name**: `geocode-location` - - **Function ID**: Wird automatisch generiert (z.B. `65a123456789abc`) - - **Runtime**: Wählen Sie `Node.js 18.0` oder höher - - **Execute Access**: `Any` (damit alle eingeloggten User die Function nutzen können) - -### 3. Code hochladen - -**Option A: Über die Console** -1. Gehen Sie zum Tab **Deployment** -2. Erstellen Sie ein neues Deployment -3. Wählen Sie **Manual** als Deployment-Methode -4. Laden Sie folgende Dateien hoch: - - `appwrite_functions/geocode-location/main.js` - - `appwrite_functions/geocode-location/package.json` -5. Setzen Sie **Entrypoint**: `main.js` -6. Klicken Sie auf **Deploy** - -**Option B: Über CLI** (wenn Appwrite CLI installiert) ```bash cd /home/digitalman/Development/flutter_tank_web_app -appwrite deploy function + +# Option A: Mit Script +./start-proxy.sh + +# Option B: Manuell +cd proxy-server +node server.js ``` -### 4. Function ID in Flutter App eintragen +Der Proxy läuft auf `http://localhost:3000` -1. Nach erfolgreichem Deployment kopieren Sie die **Function ID** -2. Öffnen Sie `lib/config/environment.dart` -3. Ersetzen Sie `YOUR_FUNCTION_ID_HERE` mit Ihrer Function ID: +### 2. Flutter App starten -```dart -static const String appwriteGeocodeFunctionId = '65a123456789abc'; // Ihre ID hier +```bash +flutter run -d chrome ``` -### 5. Testen +### 3. Testen -**In der Appwrite Console:** -1. Gehen Sie zu Ihrer Function -2. Klicken Sie auf **Execute** -3. Verwenden Sie diesen Test-Body: -```json -{ - "lat": 47.9385165, - "lon": 13.762887, - "apiKey": "NTYxMDQ3NTY2OWI3NDI5ZGIzZWIxOWNiNTNhMDEwODY6YTQ4MTJhYzYtYmYzOC00ZmE4LTk4YzYtZDBjNzYyZTAyNjBk" -} +**Geocoding Request:** +```bash +curl "http://localhost:3000/?lat=47.9385165&lon=13.762887&apiKey=YOUR_API_KEY" ``` -4. Erwartete Response: + +**Erwartete Response:** ```json { "success": true, @@ -74,44 +56,273 @@ static const String appwriteGeocodeFunctionId = '65a123456789abc'; // Ihre ID hi } ``` -**In der Flutter App:** -1. Starten Sie die App neu -2. Erstellen Sie einen neuen Tankeintrag -3. Die Standortabfrage sollte nun über den Backend-Proxy laufen -4. Sie sollten eine Erfolgs-Snackbar mit der Adresse sehen +**Health Check:** +```bash +curl http://localhost:3000/health +# Response: healthy +``` + +## 🐳 Docker Deployment (Empfohlen) + +### 1. Docker Images bauen + +```bash +# Interaktives Deployment-Script +./deploy.sh +# Wählen Sie Option 3: "Alles bauen und starten" + +# Oder manuell +docker-compose up -d --build +``` + +### 2. Services überprüfen + +```bash +docker-compose ps + +# Erwartete Ausgabe: +# flutter-tank-web Up 0.0.0.0:8090->80/tcp +# ptv-proxy Up 0.0.0.0:3000->3000/tcp +``` + +### 3. Logs prüfen + +```bash +# Proxy Logs +docker-compose logs -f ptv-proxy + +# Alle Services +docker-compose logs -f +``` + +## 🌐 Produktion - Auf Server deployen + +### Schritt 1: Server vorbereiten + +**SSH zum Server:** +```bash +ssh user@your-server.com +``` + +**Docker installieren (falls nicht vorhanden):** +```bash +curl -fsSL https://get.docker.com -o get-docker.sh +sudo sh get-docker.sh +sudo usermod -aG docker $USER +``` + +### Schritt 2: Code auf Server kopieren + +**Option A: Git** +```bash +git clone https://github.com/your-repo/flutter_tank_web_app.git +cd flutter_tank_web_app +``` + +**Option B: SCP/Rsync** +```bash +# Von lokalem Rechner +rsync -avz --exclude 'build' --exclude '.dart_tool' \ + . user@your-server.com:/opt/flutter-tank-app/ +``` + +### Schritt 3: Proxy URL konfigurieren + +Bearbeiten Sie `lib/config/environment.dart`: + +```dart +class Environment { + // Produktions-URL des Proxy Servers + static const String localProxyUrl = 'http://your-server.com:3000'; + static const bool useLocalProxy = true; + + // ... rest bleibt gleich +} +``` + +### Schritt 4: Neu builden und deployen + +```bash +cd /opt/flutter-tank-app +./deploy.sh +# Option 3: "Alles bauen und starten" +``` + +### Schritt 5: Firewall konfigurieren + +```bash +# Port 8090 (Web App) und 3000 (Proxy) öffnen +sudo ufw allow 8090/tcp +sudo ufw allow 3000/tcp +sudo ufw enable +``` + +## 🔒 Sichere Konfiguration mit Nginx (Empfohlen) + +Statt Port 3000 direkt zu exponieren, verwenden Sie Nginx als Reverse Proxy: + +### 1. Nginx konfigurieren + +```bash +sudo nano /etc/nginx/sites-available/tank.yourdomain.com +``` + +```nginx +server { + listen 80; + server_name tank.yourdomain.com; + + # Flutter Web App + location / { + proxy_pass http://localhost:8090; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # Proxy Server (API Endpoint) + location /api/geocode { + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + + # CORS Headers werden vom Proxy Server gesetzt + proxy_hide_header Access-Control-Allow-Origin; + } +} +``` + +### 2. Site aktivieren + +```bash +sudo ln -s /etc/nginx/sites-available/tanknew.joshihomeserver.ipv64.net /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx +``` + +### 3. SSL Zertifikat (Let's Encrypt) + +```bash +sudo apt install certbot python3-certbot-nginx +sudo certbot --nginx -d tanknew.joshihomeserver.ipv64.net +``` + +### 4. Environment anpassen + +```dart +static const String localProxyUrl = 'https://tanknew.joshihomeserver.ipv64.net/api/geocode'; +``` + +### 5. Firewall anpassen + +```bash +# Nur 80 und 443 öffnen (nicht 3000) +sudo ufw allow 80/tcp +sudo ufw allow 443/tcp +sudo ufw deny 3000/tcp # Proxy nur über Nginx erreichbar +``` ## 🔧 Troubleshooting -### Function ID nicht gesetzt -**Problem:** Console-Warnung: "Appwrite Function ID nicht konfiguriert" -**Lösung:** Schritt 4 nochmal durchführen und App neu starten +### Proxy Server startet nicht -### Function Execution fehlgeschlagen -**Problem:** Status ist nicht "completed" -**Lösung:** -1. Prüfen Sie die Logs in der Appwrite Console -2. Stellen Sie sicher, dass die Runtime korrekt ist -3. Prüfen Sie ob alle Dateien hochgeladen wurden +**Logs prüfen:** +```bash +docker-compose logs ptv-proxy +``` -### PTV API Fehler -**Problem:** "PTV API Fehler - Status Code: 401" +**Häufige Probleme:** +- Port 3000 bereits belegt: `sudo lsof -i :3000` +- Node.js nicht installiert: `node --version` + +### CORS-Fehler trotz Proxy + +**Prüfen:** +1. Ist der Proxy erreichbar? `curl http://localhost:3000/health` +2. Richtige URL in `environment.dart`? +3. Browser Cache leeren und App neu laden + +### "Connection refused" + +**Lösung:** +```bash +# Docker Container laufen? +docker-compose ps + +# Proxy neu starten +docker-compose restart ptv-proxy +``` + +### PTV API gibt 401 zurück + +**Problem:** Ungültiger API Key **Lösung:** API Key in `environment.dart` überprüfen -### CORS weiterhin ein Problem -**Problem:** Immer noch CORS-Fehler +### Im Container: "npm not found" + +**Problem:** Lokales `node_modules` committet **Lösung:** -1. Stellen Sie sicher, dass die alte `getNearbyLocation` Methode nicht mehr verwendet wird -2. Prüfen Sie, dass `appwriteService.geocodeLocation` aufgerufen wird -3. Cachen leeren und App neu builden +```bash +# .dockerignore prüfen +cat .dockerignore | grep node_modules + +# Sollte vorhanden sein +``` + +## 📊 Monitoring + +### Service Status + +```bash +# Docker +docker-compose ps + +# System Resources +docker stats + +# Health Check +curl http://localhost:3000/health +``` + +### Logs Live anschauen + +```bash +# Proxy +docker-compose logs -f ptv-proxy + +# Alle Services +docker-compose logs -f --tail=100 +``` + +## 🔄 Updates deployen + +```bash +# Code aktualisieren +git pull + +# Container neu bauen und starten +docker-compose up -d --build + +# Alte Images aufräumen +docker image prune -f +``` ## ✅ Erfolgskriterien Nach erfolgreichem Deployment sollten Sie: -- ✅ Eine Erfolgs-Snackbar mit Adresse sehen (nicht nur Koordinaten) -- ✅ Keine CORS-Fehler mehr in der Browser-Console -- ✅ In den Logs: "📍 Verwende Backend-Proxy für Geocoding..." -- ✅ In den Logs: "✅ Geocoding erfolgreich: [Adresse]" +- ✅ Proxy Health Check erfolgreich: `curl http://tanknew.joshihomeserver.ipv64.net:3000/health` +- ✅ Geocoding funktioniert in der App +- ✅ Browser Console zeigt: "🔄 Verwende lokalen Proxy..." +- ✅ Browser Console zeigt: "✅ Geocoding erfolgreich (Proxy): [Adresse]" +- ✅ Keine CORS-Fehler mehr -## 📝 Alternative ohne Deployment +## 📝 Produktions-Checkliste -Falls Sie die Function nicht deployen möchten, wird automatisch auf Koordinaten-Speicherung zurückgegriffen. Die App funktioniert weiterhin, speichert aber `Lat: XX.XXXXXX, Lon: YY.YYYYYY` statt der Adresse. +- [ ] Docker und Docker Compose installiert +- [ ] Code auf Server übertragen +- [ ] `localProxyUrl` in environment.dart angepasst +- [ ] Docker Containers laufen (`docker-compose ps`) +- [ ] Firewall konfiguriert +- [ ] Nginx Reverse Proxy eingerichtet (empfohlen) +- [ ] SSL Zertifikat installiert +- [ ] Health Checks erfolgreich +- [ ] Geocoding in App getestet diff --git a/Dockerfile b/Dockerfile index f378cb3..f676e70 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,19 +20,21 @@ ENV FLUTTER_HOME=/usr/local/flutter ENV PATH="${FLUTTER_HOME}/bin:${PATH}" RUN git clone https://github.com/flutter/flutter.git ${FLUTTER_HOME} -b stable --depth 1 && \ - flutter config --enable-web && \ - flutter precache --web + flutter config --enable-web --no-analytics && \ + flutter doctor -v # Set working directory WORKDIR /app # Copy app files COPY pubspec.yaml pubspec.lock ./ + +# Run pub get (downloads web dependencies without needing gradle) RUN flutter pub get COPY . . -# Build web app +# Build web app (downloads web artifacts on-demand without gradle) RUN flutter build web --release --web-renderer canvaskit # Production stage - Nginx diff --git a/deploy.sh b/deploy.sh index 2881e23..53acc36 100755 --- a/deploy.sh +++ b/deploy.sh @@ -57,7 +57,7 @@ case $option in echo -e "${GREEN}✅ Services gestartet!${NC}" echo "" echo -e "${YELLOW}📡 Verfügbare Endpoints:${NC}" - echo -e " Flutter Web App: ${GREEN}http://localhost:8080${NC}" + echo -e " Flutter Web App: ${GREEN}http://localhost:8090${NC}" echo -e " Proxy Server: ${GREEN}http://localhost:3000${NC}" echo "" echo -e "${YELLOW}📊 Status prüfen:${NC}" diff --git a/docker-compose.yml b/docker-compose.yml index ddd0065..d5f4c31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: # Flutter Web App flutter-tank-web: @@ -9,14 +7,14 @@ services: container_name: flutter-tank-web restart: unless-stopped ports: - - "8080:80" + - "8090:80" networks: - app-network environment: - TZ=Europe/Vienna labels: - "traefik.enable=true" - - "traefik.http.routers.flutter-tank.rule=Host(`tank.yourdomain.com`)" + - "traefik.http.routers.flutter-tank.rule=Host(`tanknew.joshihomeserver.ipv64.net`)" - "traefik.http.routers.flutter-tank.entrypoints=websecure" - "traefik.http.routers.flutter-tank.tls.certresolver=letsencrypt" - "traefik.http.services.flutter-tank.loadbalancer.server.port=80" diff --git a/lib/controller/edit_controller.dart b/lib/controller/edit_controller.dart index a5638c3..94674e3 100644 --- a/lib/controller/edit_controller.dart +++ b/lib/controller/edit_controller.dart @@ -244,4 +244,8 @@ class EditController extends GetxController { locationController.dispose(); super.onClose(); } + + void gotToList() { + Get.offAllNamed(HomePage.namedRoute); + } } diff --git a/lib/pages/edit_view.dart b/lib/pages/edit_view.dart index 600960a..6f46048 100644 --- a/lib/pages/edit_view.dart +++ b/lib/pages/edit_view.dart @@ -24,7 +24,7 @@ class EditPage extends GetView { centerTitle: true, leading: IconButton( icon: const Icon(Icons.arrow_back), - onPressed: () => Get.back(), + onPressed: () => editCtrl.gotToList(), ), ), body: Container( @@ -266,7 +266,7 @@ class EditPage extends GetView { SizedBox( width: double.infinity, child: OutlinedButton( - onPressed: () => Get.back(), + onPressed: () => editCtrl.gotToList(), style: OutlinedButton.styleFrom( foregroundColor: Colors.white, side: const BorderSide(color: Colors.white, width: 2), diff --git a/lib/pages/login_view.dart b/lib/pages/login_view.dart index 8e0bf0f..f7962f4 100644 --- a/lib/pages/login_view.dart +++ b/lib/pages/login_view.dart @@ -19,7 +19,7 @@ class LoginPage extends GetView { width: displayWidth, padding: const EdgeInsets.symmetric( horizontal: 16.0, - vertical: 130.0, + vertical: 100.0, ), color: Colors.blue.shade100, child: SingleChildScrollView( diff --git a/lib/pages/signin_view.dart b/lib/pages/signin_view.dart index b77639b..64f766a 100644 --- a/lib/pages/signin_view.dart +++ b/lib/pages/signin_view.dart @@ -17,10 +17,7 @@ class SigninPage extends GetView { body: Container( height: displayHeight, width: displayWidth, - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 100.0, - ), + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 90.0), color: Colors.blue.shade100, child: SingleChildScrollView( child: MySigninWidget( diff --git a/lib/widgets/my_login_widget.dart b/lib/widgets/my_login_widget.dart index 5602f1c..70848f1 100644 --- a/lib/widgets/my_login_widget.dart +++ b/lib/widgets/my_login_widget.dart @@ -58,8 +58,8 @@ class MyLoginWidget extends StatelessWidget { borderRadius: BorderRadius.circular(18), child: Image.asset( 'assets/images/guru.png', - width: 400, - height: 400, + width: 300, + height: 300, ), ), ), diff --git a/lib/widgets/my_signin_widget.dart b/lib/widgets/my_signin_widget.dart index fffef7f..7143199 100644 --- a/lib/widgets/my_signin_widget.dart +++ b/lib/widgets/my_signin_widget.dart @@ -58,8 +58,8 @@ class MySigninWidget extends StatelessWidget { borderRadius: BorderRadius.circular(18), child: Image.asset( 'assets/images/guru01.png', - width: 400, - height: 400, + width: 300, + height: 300, ), ), ),