mod divers data
This commit is contained in:
@@ -1,56 +0,0 @@
|
|||||||
# .dockerignore
|
|
||||||
# Git
|
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
*~
|
|
||||||
|
|
||||||
# Flutter/Dart
|
|
||||||
.dart_tool/
|
|
||||||
.packages
|
|
||||||
build/
|
|
||||||
.flutter-plugins
|
|
||||||
.flutter-plugins-dependencies
|
|
||||||
.metadata
|
|
||||||
|
|
||||||
# Node.js (for proxy)
|
|
||||||
node_modules/
|
|
||||||
npm-debug.log
|
|
||||||
yarn-error.log
|
|
||||||
|
|
||||||
# Test
|
|
||||||
test/
|
|
||||||
integration_test/
|
|
||||||
.test_coverage/
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
*.md
|
|
||||||
!README.md
|
|
||||||
|
|
||||||
# CI/CD
|
|
||||||
.github/
|
|
||||||
|
|
||||||
# Local development
|
|
||||||
.env.local
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
*~
|
|
||||||
|
|
||||||
# Other
|
|
||||||
*.iml
|
|
||||||
*.class
|
|
||||||
*.lock
|
|
||||||
!pubspec.lock
|
|
||||||
!package-lock.json
|
|
||||||
328
DEPLOYMENT.md
328
DEPLOYMENT.md
@@ -1,328 +0,0 @@
|
|||||||
# Proxy Server Deployment - Anleitung
|
|
||||||
|
|
||||||
## 📋 Übersicht
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## 🏗️ Architektur
|
|
||||||
|
|
||||||
```
|
|
||||||
Browser (Flutter Web App)
|
|
||||||
↓
|
|
||||||
Proxy Server (localhost:3000 / your-server.com:3000)
|
|
||||||
↓
|
|
||||||
PTV Geocoding API (api.myptv.com)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 Lokale Entwicklung
|
|
||||||
|
|
||||||
### 1. Proxy Server starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /home/digitalman/Development/flutter_tank_web_app
|
|
||||||
|
|
||||||
# Option A: Mit Script
|
|
||||||
./start-proxy.sh
|
|
||||||
|
|
||||||
# Option B: Manuell
|
|
||||||
cd proxy-server
|
|
||||||
node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Proxy läuft auf `http://localhost:3000`
|
|
||||||
|
|
||||||
### 2. Flutter App starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
flutter run -d chrome
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Testen
|
|
||||||
|
|
||||||
**Geocoding Request:**
|
|
||||||
```bash
|
|
||||||
curl "http://localhost:3000/?lat=47.9385165&lon=13.762887&apiKey=YOUR_API_KEY"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Erwartete Response:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"location": "Straßenname Hausnummer, PLZ Stadt",
|
|
||||||
"coordinates": {
|
|
||||||
"lat": 47.9385165,
|
|
||||||
"lon": 13.762887
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**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
|
|
||||||
|
|
||||||
### Proxy Server startet nicht
|
|
||||||
|
|
||||||
**Logs prüfen:**
|
|
||||||
```bash
|
|
||||||
docker-compose logs ptv-proxy
|
|
||||||
```
|
|
||||||
|
|
||||||
**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
|
|
||||||
|
|
||||||
### Im Container: "npm not found"
|
|
||||||
|
|
||||||
**Problem:** Lokales `node_modules` committet
|
|
||||||
**Lösung:**
|
|
||||||
```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:
|
|
||||||
- ✅ 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
|
|
||||||
|
|
||||||
## 📝 Produktions-Checkliste
|
|
||||||
|
|
||||||
- [ ] 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
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
# 🐳 Docker Deployment Anleitung
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Docker installiert (`docker --version`)
|
|
||||||
- Docker Compose installiert (`docker-compose --version`)
|
|
||||||
- Min. 2 GB freier RAM
|
|
||||||
- Min. 5 GB freier Speicherplatz
|
|
||||||
|
|
||||||
## 🚀 Schnellstart
|
|
||||||
|
|
||||||
### Option 1: Mit Deploy-Script (Empfohlen)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./deploy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Folgen Sie den Anweisungen im interaktiven Menü.
|
|
||||||
|
|
||||||
### Option 2: Manuelle Commands
|
|
||||||
|
|
||||||
**Alles bauen und starten:**
|
|
||||||
```bash
|
|
||||||
docker-compose up -d --build
|
|
||||||
```
|
|
||||||
|
|
||||||
**Nur starten (bereits gebaut):**
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
**Stoppen:**
|
|
||||||
```bash
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
**Logs anzeigen:**
|
|
||||||
```bash
|
|
||||||
docker-compose logs -f
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📦 Was wird deployed?
|
|
||||||
|
|
||||||
### 1. Flutter Web App Container
|
|
||||||
- **Image:** `flutter-tank-web:latest`
|
|
||||||
- **Port:** 8080 (Host) → 80 (Container)
|
|
||||||
- **URL:** `http://localhost:8080`
|
|
||||||
- **Technologie:** Flutter Web + Nginx
|
|
||||||
|
|
||||||
### 2. Proxy Server Container (Optional)
|
|
||||||
- **Image:** `ptv-proxy:latest`
|
|
||||||
- **Port:** 3000 (Host) → 3000 (Container)
|
|
||||||
- **URL:** `http://localhost:3000`
|
|
||||||
- **Technologie:** Node.js
|
|
||||||
|
|
||||||
## 🏗️ Build-Prozess
|
|
||||||
|
|
||||||
Der Build läuft in 2 Phasen:
|
|
||||||
|
|
||||||
**Phase 1: Flutter Build (Multi-Stage)**
|
|
||||||
1. Ubuntu base image
|
|
||||||
2. Flutter SDK installieren
|
|
||||||
3. Dependencies installieren (`flutter pub get`)
|
|
||||||
4. Web App bauen (`flutter build web`)
|
|
||||||
|
|
||||||
**Phase 2: Production (Nginx)**
|
|
||||||
1. Alpine Nginx image
|
|
||||||
2. Gebaute App kopieren
|
|
||||||
3. Nginx konfigurieren
|
|
||||||
4. Port 80 exponieren
|
|
||||||
|
|
||||||
**Geschätzte Build-Zeit:** 5-10 Minuten (beim ersten Mal)
|
|
||||||
|
|
||||||
## 🌐 Auf Server deployen
|
|
||||||
|
|
||||||
### 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
|
|
||||||
```
|
|
||||||
|
|
||||||
**Docker Compose installieren:**
|
|
||||||
```bash
|
|
||||||
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
|
||||||
sudo chmod +x /usr/local/bin/docker-compose
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Code auf Server übertragen
|
|
||||||
|
|
||||||
**Option A: Git Clone**
|
|
||||||
```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 aus
|
|
||||||
rsync -avz --exclude 'build' --exclude '.dart_tool' \
|
|
||||||
/home/digitalman/Development/flutter_tank_web_app/ \
|
|
||||||
user@your-server.com:/opt/flutter-tank-app/
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Environment anpassen
|
|
||||||
|
|
||||||
Bearbeiten Sie `lib/config/environment.dart`:
|
|
||||||
```dart
|
|
||||||
static const bool useLocalProxy = false; // Für Produktion
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Deployen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /opt/flutter-tank-app
|
|
||||||
./deploy.sh
|
|
||||||
# Wählen Sie Option 3: "Alles bauen und starten"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Mit Domain verbinden (Optional)
|
|
||||||
|
|
||||||
**Nginx Reverse Proxy konfigurieren:**
|
|
||||||
```nginx
|
|
||||||
# /etc/nginx/sites-available/tank.yourdomain.com
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name tank.yourdomain.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:8080;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Aktivieren:**
|
|
||||||
```bash
|
|
||||||
sudo ln -s /etc/nginx/sites-available/tank.yourdomain.com /etc/nginx/sites-enabled/
|
|
||||||
sudo nginx -t
|
|
||||||
sudo systemctl reload nginx
|
|
||||||
```
|
|
||||||
|
|
||||||
**SSL mit Let's Encrypt:**
|
|
||||||
```bash
|
|
||||||
sudo apt install certbot python3-certbot-nginx
|
|
||||||
sudo certbot --nginx -d tank.yourdomain.com
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Konfiguration
|
|
||||||
|
|
||||||
### Ports ändern
|
|
||||||
|
|
||||||
In `docker-compose.yml`:
|
|
||||||
```yaml
|
|
||||||
ports:
|
|
||||||
- "8080:80" # Ändern Sie 8080 auf gewünschten Port
|
|
||||||
```
|
|
||||||
|
|
||||||
### Umgebungsvariablen
|
|
||||||
|
|
||||||
Erstellen Sie `.env` Datei:
|
|
||||||
```env
|
|
||||||
# App Settings
|
|
||||||
APP_PORT=8080
|
|
||||||
PROXY_PORT=3000
|
|
||||||
|
|
||||||
# Domain (für Traefik)
|
|
||||||
DOMAIN=tank.yourdomain.com
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mit Traefik (Reverse Proxy)
|
|
||||||
|
|
||||||
Die `docker-compose.yml` enthält bereits Traefik Labels.
|
|
||||||
|
|
||||||
**Traefik setup:**
|
|
||||||
```yaml
|
|
||||||
# docker-compose.traefik.yml
|
|
||||||
version: '3.8'
|
|
||||||
services:
|
|
||||||
traefik:
|
|
||||||
image: traefik:v2.10
|
|
||||||
command:
|
|
||||||
- "--providers.docker=true"
|
|
||||||
- "--entrypoints.web.address=:80"
|
|
||||||
- "--entrypoints.websecure.address=:443"
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.email=your@email.com"
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
||||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
- "443:443"
|
|
||||||
volumes:
|
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
||||||
- "./letsencrypt:/letsencrypt"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📊 Monitoring
|
|
||||||
|
|
||||||
### Container Status prüfen
|
|
||||||
```bash
|
|
||||||
docker-compose ps
|
|
||||||
```
|
|
||||||
|
|
||||||
### Logs anschauen
|
|
||||||
```bash
|
|
||||||
# Alle Services
|
|
||||||
docker-compose logs -f
|
|
||||||
|
|
||||||
# Nur Web App
|
|
||||||
docker-compose logs -f flutter-tank-web
|
|
||||||
|
|
||||||
# Nur Proxy
|
|
||||||
docker-compose logs -f ptv-proxy
|
|
||||||
```
|
|
||||||
|
|
||||||
### Resource Usage
|
|
||||||
```bash
|
|
||||||
docker stats
|
|
||||||
```
|
|
||||||
|
|
||||||
### Health Check
|
|
||||||
```bash
|
|
||||||
# Web App
|
|
||||||
curl http://localhost:8080/health
|
|
||||||
|
|
||||||
# Proxy
|
|
||||||
curl http://localhost:3000/health
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 Updates deployen
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Code aktualisieren
|
|
||||||
git pull
|
|
||||||
|
|
||||||
# Neu bauen und starten
|
|
||||||
docker-compose up -d --build
|
|
||||||
|
|
||||||
# Alte Images aufräumen
|
|
||||||
docker image prune -f
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🛠️ Troubleshooting
|
|
||||||
|
|
||||||
### Container startet nicht
|
|
||||||
```bash
|
|
||||||
# Logs prüfen
|
|
||||||
docker-compose logs flutter-tank-web
|
|
||||||
|
|
||||||
# Container Status
|
|
||||||
docker-compose ps
|
|
||||||
|
|
||||||
# Neu starten
|
|
||||||
docker-compose restart flutter-tank-web
|
|
||||||
```
|
|
||||||
|
|
||||||
### Port bereits belegt
|
|
||||||
```bash
|
|
||||||
# Prozess auf Port finden
|
|
||||||
sudo lsof -i :8080
|
|
||||||
|
|
||||||
# Port in docker-compose.yml ändern
|
|
||||||
```
|
|
||||||
|
|
||||||
### Out of Memory
|
|
||||||
```bash
|
|
||||||
# Docker Memory Limit erhöhen
|
|
||||||
# In docker-compose.yml unter service:
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 2G
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build schlägt fehl
|
|
||||||
```bash
|
|
||||||
# Docker Cache leeren
|
|
||||||
docker builder prune -a
|
|
||||||
|
|
||||||
# Komplett neu bauen
|
|
||||||
docker-compose build --no-cache
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📦 Backup & Restore
|
|
||||||
|
|
||||||
### Volumes sichern
|
|
||||||
```bash
|
|
||||||
# Data Volume backup
|
|
||||||
docker run --rm -v flutter-tank-data:/data -v $(pwd):/backup alpine tar czf /backup/data-backup.tar.gz -C /data .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Image speichern
|
|
||||||
```bash
|
|
||||||
# Image exportieren
|
|
||||||
docker save flutter-tank-web:latest | gzip > flutter-tank-web.tar.gz
|
|
||||||
|
|
||||||
# Image importieren
|
|
||||||
docker load < flutter-tank-web.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔒 Sicherheit
|
|
||||||
|
|
||||||
### Best Practices
|
|
||||||
|
|
||||||
1. **Nicht als Root laufen** (bereits in Proxy-Dockerfile implementiert)
|
|
||||||
2. **Security Headers** (bereits in nginx.conf)
|
|
||||||
3. **Firewall konfigurieren:**
|
|
||||||
```bash
|
|
||||||
sudo ufw allow 80/tcp
|
|
||||||
sudo ufw allow 443/tcp
|
|
||||||
sudo ufw enable
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Regular Updates:**
|
|
||||||
```bash
|
|
||||||
# Base images updaten
|
|
||||||
docker-compose pull
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🎯 Performance Optimierung
|
|
||||||
|
|
||||||
### Nginx Caching
|
|
||||||
Bereits in `nginx.conf` konfiguriert:
|
|
||||||
- Static assets: 1 Jahr Cache
|
|
||||||
- Gzip Kompression aktiv
|
|
||||||
|
|
||||||
### Docker Image Size
|
|
||||||
```bash
|
|
||||||
# Image Größe prüfen
|
|
||||||
docker images flutter-tank-web
|
|
||||||
|
|
||||||
# Multi-stage build reduziert Größe bereits deutlich
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 Checkliste Produktion
|
|
||||||
|
|
||||||
- [ ] `useLocalProxy = false` in environment.dart
|
|
||||||
- [ ] Domain konfiguriert
|
|
||||||
- [ ] SSL Zertifikat installiert
|
|
||||||
- [ ] Firewall konfiguriert
|
|
||||||
- [ ] Backup-Strategie definiert
|
|
||||||
- [ ] Monitoring eingerichtet
|
|
||||||
- [ ] Logs rotieren konfiguriert
|
|
||||||
- [ ] Update-Prozess dokumentiert
|
|
||||||
|
|
||||||
## 🆘 Support
|
|
||||||
|
|
||||||
Bei Problemen:
|
|
||||||
1. Logs prüfen: `docker-compose logs`
|
|
||||||
2. Container Status: `docker-compose ps`
|
|
||||||
3. Health Checks: `curl http://localhost:8080/health`
|
|
||||||
4. Docker System: `docker system df`
|
|
||||||
54
Dockerfile
54
Dockerfile
@@ -1,54 +0,0 @@
|
|||||||
# Dockerfile für Flutter Web App
|
|
||||||
FROM ubuntu:22.04 AS build
|
|
||||||
|
|
||||||
# Avoid interactive prompts
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
curl \
|
|
||||||
git \
|
|
||||||
unzip \
|
|
||||||
xz-utils \
|
|
||||||
zip \
|
|
||||||
libglu1-mesa \
|
|
||||||
wget \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Flutter
|
|
||||||
ENV FLUTTER_HOME=/usr/local/flutter
|
|
||||||
ENV PATH="${FLUTTER_HOME}/bin:${PATH}"
|
|
||||||
ENV TAR_OPTIONS=--no-same-owner
|
|
||||||
|
|
||||||
RUN git clone https://github.com/flutter/flutter.git ${FLUTTER_HOME} -b stable --depth 1 && \
|
|
||||||
flutter config --enable-web --no-analytics && \
|
|
||||||
flutter precache --web
|
|
||||||
|
|
||||||
# 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 (web-only artifacts; suppress wasm dry-run warnings)
|
|
||||||
RUN flutter build web --release --no-wasm-dry-run
|
|
||||||
|
|
||||||
# Production stage - Nginx
|
|
||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
# Copy built app to nginx
|
|
||||||
COPY --from=build /app/build/web /usr/share/nginx/html
|
|
||||||
|
|
||||||
# Copy custom nginx config
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# Start nginx
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# 🚀 Quick Start - Lokaler Reverse Proxy
|
|
||||||
|
|
||||||
## Sofort loslegen
|
|
||||||
|
|
||||||
### Terminal 1: Proxy Server starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./start-proxy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Oder manuell:
|
|
||||||
```bash
|
|
||||||
cd proxy-server
|
|
||||||
node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### Terminal 2: Flutter App starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
flutter run -d chrome
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ Das wars!
|
|
||||||
|
|
||||||
Die App verwendet jetzt automatisch den lokalen Proxy auf `http://localhost:3000` für Geocoding.
|
|
||||||
|
|
||||||
## 🔧 Konfiguration
|
|
||||||
|
|
||||||
In [lib/config/environment.dart](lib/config/environment.dart):
|
|
||||||
|
|
||||||
```dart
|
|
||||||
static const bool useLocalProxy = true; // true = Proxy, false = Appwrite Function
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📋 Checkliste
|
|
||||||
|
|
||||||
- ✅ Node.js installiert (`node --version`)
|
|
||||||
- ✅ Proxy läuft (`http://localhost:3000` im Browser)
|
|
||||||
- ✅ `useLocalProxy = true` in environment.dart
|
|
||||||
- ✅ Flutter App läuft
|
|
||||||
|
|
||||||
## 🎯 Vorteile Lokaler Proxy
|
|
||||||
|
|
||||||
✅ **Kein CORS-Problem** - Server umgeht Browser-Beschränkungen
|
|
||||||
✅ **Schnelles Testen** - Kein Cloud-Deployment nötig
|
|
||||||
✅ **Einfaches Debugging** - Logs direkt im Terminal
|
|
||||||
✅ **Kostenlos** - Läuft lokal, keine Cloud-Kosten
|
|
||||||
|
|
||||||
## 🌐 Für Produktion
|
|
||||||
|
|
||||||
Für den Live-Betrieb:
|
|
||||||
|
|
||||||
1. Setzen Sie `useLocalProxy = false`
|
|
||||||
2. Deployen Sie die Appwrite Function (siehe [DEPLOYMENT.md](DEPLOYMENT.md))
|
|
||||||
3. Tragen Sie die Function ID ein
|
|
||||||
|
|
||||||
## 📊 Vergleich
|
|
||||||
|
|
||||||
| Feature | Lokaler Proxy | Appwrite Function |
|
|
||||||
|---------|--------------|-------------------|
|
|
||||||
| Setup Zeit | < 1 Minute | ~10 Minuten |
|
|
||||||
| CORS | ✅ Gelöst | ✅ Gelöst |
|
|
||||||
| Kosten | Kostenlos | Serverless (minimal) |
|
|
||||||
| Verwendung | Nur Entwicklung | Entwicklung + Produktion |
|
|
||||||
| Debugging | Sehr einfach | Logs in Console |
|
|
||||||
| Offline | ❌ | ❌ |
|
|
||||||
|
|
||||||
## 🐛 Problemlösung
|
|
||||||
|
|
||||||
**Proxy startet nicht:**
|
|
||||||
```bash
|
|
||||||
# Port 3000 belegt?
|
|
||||||
lsof -i :3000
|
|
||||||
# Prozess beenden
|
|
||||||
kill -9 <PID>
|
|
||||||
```
|
|
||||||
|
|
||||||
**App findet Proxy nicht:**
|
|
||||||
- Proxy läuft? Prüfen Sie `http://localhost:3000` im Browser
|
|
||||||
- `useLocalProxy = true`? Prüfen Sie environment.dart
|
|
||||||
- Hot Restart in Flutter machen
|
|
||||||
|
|
||||||
**Immer noch CORS-Fehler:**
|
|
||||||
- Browser-Cache leeren
|
|
||||||
- DevTools → Network → "Disable cache"
|
|
||||||
- App neu builden: `flutter run -d chrome`
|
|
||||||
111
STATUS.md
111
STATUS.md
@@ -1,111 +0,0 @@
|
|||||||
# ✅ System Status - Alles Repariert
|
|
||||||
|
|
||||||
## 📋 Überprüfungsergebnis
|
|
||||||
|
|
||||||
### ✅ Alle Fehler behoben!
|
|
||||||
|
|
||||||
**Probleme die behoben wurden:**
|
|
||||||
1. ❌ Syntax-Fehler in edit_controller.dart → ✅ Behoben
|
|
||||||
2. ❌ Fehlende Imports → ✅ Hinzugefügt
|
|
||||||
3. ❌ Unvollständige Methoden → ✅ Implementiert
|
|
||||||
4. ❌ Duplicate Code → ✅ Entfernt
|
|
||||||
|
|
||||||
## 🎯 Aktueller Status
|
|
||||||
|
|
||||||
### 1. Edit Controller ✅
|
|
||||||
- [x] Keine Compile-Fehler
|
|
||||||
- [x] Verwendet `appwriteService.geocodeLocation()`
|
|
||||||
- [x] Benutzer-Feedback mit Snackbars
|
|
||||||
- [x] Saubere Imports
|
|
||||||
|
|
||||||
### 2. Appwrite Service ✅
|
|
||||||
- [x] `geocodeLocation()` Methode implementiert
|
|
||||||
- [x] `_geocodeViaLocalProxy()` für lokalen Proxy
|
|
||||||
- [x] Fallback auf Koordinaten bei Fehlern
|
|
||||||
- [x] http package importiert
|
|
||||||
|
|
||||||
### 3. Environment Config ✅
|
|
||||||
```dart
|
|
||||||
static const bool useLocalProxy = true; // ✅ Aktiv
|
|
||||||
static const String localProxyUrl = 'http://localhost:3000';
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Proxy Server ✅
|
|
||||||
- [x] server.js existiert
|
|
||||||
- [x] package.json existiert
|
|
||||||
- [x] README.md vorhanden
|
|
||||||
- [x] Node.js funktioniert
|
|
||||||
- [x] Start-Script ausführbar
|
|
||||||
|
|
||||||
## 🚀 So starten Sie die App
|
|
||||||
|
|
||||||
### Terminal 1: Proxy Server
|
|
||||||
```bash
|
|
||||||
cd /home/digitalman/Development/flutter_tank_web_app
|
|
||||||
./start-proxy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Terminal 2: Flutter App
|
|
||||||
```bash
|
|
||||||
cd /home/digitalman/Development/flutter_tank_web_app
|
|
||||||
flutter run -d chrome
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📊 Funktionsweise
|
|
||||||
|
|
||||||
```
|
|
||||||
User erstellt Tankeintrag
|
|
||||||
↓
|
|
||||||
Geolocation fragt GPS ab
|
|
||||||
↓
|
|
||||||
EditController ruft appwriteService.geocodeLocation() auf
|
|
||||||
↓
|
|
||||||
AppwriteService prüft useLocalProxy Flag
|
|
||||||
↓
|
|
||||||
├─ true → Lokaler Proxy (localhost:3000) → PTV API ✅
|
|
||||||
└─ false → Fallback auf Koordinaten
|
|
||||||
↓
|
|
||||||
Adresse oder Koordinaten werden gespeichert
|
|
||||||
```
|
|
||||||
|
|
||||||
## ✅ Erfolgskriterien
|
|
||||||
|
|
||||||
Wenn alles funktioniert, sehen Sie:
|
|
||||||
- ✅ Proxy-Server läuft auf Port 3000
|
|
||||||
- ✅ "🔄 Verwende lokalen Proxy" in Logs
|
|
||||||
- ✅ "✅ Geocoding erfolgreich (Proxy): [Adresse]"
|
|
||||||
- ✅ Grüne Snackbar mit Adresse in der App
|
|
||||||
- ✅ Keine CORS-Fehler in Browser Console
|
|
||||||
|
|
||||||
## 🐛 Wenn etwas nicht funktioniert
|
|
||||||
|
|
||||||
**Proxy nicht erreichbar:**
|
|
||||||
```bash
|
|
||||||
# Prüfen ob läuft
|
|
||||||
curl http://localhost:3000
|
|
||||||
# Neu starten
|
|
||||||
./start-proxy.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
**Flutter App zeigt Koordinaten statt Adresse:**
|
|
||||||
1. Prüfen: Proxy läuft?
|
|
||||||
2. Prüfen: `useLocalProxy = true`?
|
|
||||||
3. Browser Console für Fehler prüfen
|
|
||||||
4. Hot Restart: `r` im Flutter Terminal
|
|
||||||
|
|
||||||
**Port 3000 belegt:**
|
|
||||||
```bash
|
|
||||||
# Prozess finden und beenden
|
|
||||||
lsof -i :3000
|
|
||||||
kill -9 <PID>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 Nächste Schritte
|
|
||||||
|
|
||||||
1. **Testen**: Neuen Tankeintrag erstellen
|
|
||||||
2. **Verifizieren**: Adresse wird korrekt angezeigt
|
|
||||||
3. **Optional**: Für Produktion auf `useLocalProxy = false` setzen
|
|
||||||
|
|
||||||
## 🎉 Status: BEREIT FÜR NUTZUNG!
|
|
||||||
|
|
||||||
Alle Systeme sind operationsbereit. Der lokale Reverse-Proxy umgeht das CORS-Problem erfolgreich.
|
|
||||||
85
deploy.sh
85
deploy.sh
@@ -1,85 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Farben
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
|
||||||
echo -e "${BLUE} Flutter Tank App - Docker Deployment${NC}"
|
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Prüfen ob Docker installiert ist
|
|
||||||
if ! command -v docker &> /dev/null; then
|
|
||||||
echo -e "${RED}❌ Docker ist nicht installiert!${NC}"
|
|
||||||
echo -e "${YELLOW}Installieren Sie Docker: https://docs.docker.com/get-docker/${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v docker-compose &> /dev/null; then
|
|
||||||
echo -e "${RED}❌ Docker Compose ist nicht installiert!${NC}"
|
|
||||||
echo -e "${YELLOW}Installieren Sie Docker Compose: https://docs.docker.com/compose/install/${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✅ Docker und Docker Compose gefunden${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Build Option
|
|
||||||
echo -e "${YELLOW}Wählen Sie eine Option:${NC}"
|
|
||||||
echo "1) Nur Flutter Web App bauen"
|
|
||||||
echo "2) Flutter Web App + Proxy Server bauen"
|
|
||||||
echo "3) Alles bauen und starten"
|
|
||||||
echo "4) Nur starten (ohne neu zu bauen)"
|
|
||||||
echo "5) Stoppen"
|
|
||||||
echo "6) Logs anzeigen"
|
|
||||||
read -p "Option (1-6): " option
|
|
||||||
|
|
||||||
case $option in
|
|
||||||
1)
|
|
||||||
echo -e "${BLUE}🔨 Baue Flutter Web App...${NC}"
|
|
||||||
docker build -t flutter-tank-web:latest .
|
|
||||||
echo -e "${GREEN}✅ Build abgeschlossen!${NC}"
|
|
||||||
echo -e "${YELLOW}Zum Starten: docker run -p 8080:80 flutter-tank-web:latest${NC}"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
echo -e "${BLUE}🔨 Baue alle Images...${NC}"
|
|
||||||
docker-compose build
|
|
||||||
echo -e "${GREEN}✅ Build abgeschlossen!${NC}"
|
|
||||||
;;
|
|
||||||
3)
|
|
||||||
echo -e "${BLUE}🔨 Baue und starte alle Services...${NC}"
|
|
||||||
docker-compose up -d --build
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}✅ Services gestartet!${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}📡 Verfügbare Endpoints:${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}"
|
|
||||||
docker-compose ps
|
|
||||||
;;
|
|
||||||
4)
|
|
||||||
echo -e "${BLUE}🚀 Starte Services...${NC}"
|
|
||||||
docker-compose up -d
|
|
||||||
echo -e "${GREEN}✅ Services gestartet!${NC}"
|
|
||||||
docker-compose ps
|
|
||||||
;;
|
|
||||||
5)
|
|
||||||
echo -e "${BLUE}🛑 Stoppe Services...${NC}"
|
|
||||||
docker-compose down
|
|
||||||
echo -e "${GREEN}✅ Services gestoppt!${NC}"
|
|
||||||
;;
|
|
||||||
6)
|
|
||||||
echo -e "${BLUE}📋 Zeige Logs...${NC}"
|
|
||||||
docker-compose logs -f
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo -e "${RED}❌ Ungültige Option${NC}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
services:
|
|
||||||
# Flutter Web App
|
|
||||||
flutter-tank-web:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: flutter-tank-web
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "8090:80"
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
environment:
|
|
||||||
- TZ=Europe/Vienna
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "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"
|
|
||||||
|
|
||||||
# Optional: Reverse Proxy für PTV API (Production)
|
|
||||||
ptv-proxy:
|
|
||||||
build:
|
|
||||||
context: ./proxy-server
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: ptv-proxy
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "3000:3000"
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- PORT=3000
|
|
||||||
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
||||||
@@ -5,17 +5,6 @@ class Environment {
|
|||||||
static const String appwriteProjectName = 'Flutter Projects';
|
static const String appwriteProjectName = 'Flutter Projects';
|
||||||
static const String appwriteRealtimeCollectionId = '68a22f520035a95d6666';
|
static const String appwriteRealtimeCollectionId = '68a22f520035a95d6666';
|
||||||
static const String appwriteDatabaseId = '68a22ef90021b90f0f43';
|
static const String appwriteDatabaseId = '68a22ef90021b90f0f43';
|
||||||
static const String ptvApiKey =
|
|
||||||
'NTYxMDQ3NTY2OWI3NDI5ZGIzZWIxOWNiNTNhMDEwODY6YTQ4MTJhYzYtYmYzOC00ZmE4LTk4YzYtZDBjNzYyZTAyNjBk';
|
|
||||||
static const String locationIQKey = 'pk.dea65023dc6fed25c96902bb97fb231d';
|
static const String locationIQKey = 'pk.dea65023dc6fed25c96902bb97fb231d';
|
||||||
static const double lat=47.93875449671056;
|
static const String locationIQBaseUrl = 'https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&';
|
||||||
static const double lon=13.762706553431048;
|
|
||||||
//https://eu1.locationiq.com/v1/reverse?key=pk.dea65023dc6fed25c96902bb97fb231d&lat=47.93875449671056&lon=13.762706553431048&format=json
|
|
||||||
static const String locationIQBaseUrl =
|
|
||||||
'https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&'; //47.93875449671056, 13.762706553431048
|
|
||||||
static const String ptvApiVersion = '3';
|
|
||||||
// Lokaler Reverse Proxy für Entwicklung (CORS-Workaround)
|
|
||||||
static const String localProxyUrl = 'http://localhost:3000';
|
|
||||||
static const bool useLocalProxy =
|
|
||||||
true; // true = lokaler Proxy, false = Appwrite Function
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter_tank_web_app/services/appwrite_service.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import '../models/tank_model.dart';
|
import '../models/tank_model.dart';
|
||||||
import '../pages/edit_view.dart';
|
import '../pages/edit_view.dart';
|
||||||
|
import '../services/appwrite_service.dart';
|
||||||
|
|
||||||
class DetailController extends GetxController {
|
class DetailController extends GetxController {
|
||||||
late TankModel tank;
|
late TankModel tank;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
|
||||||
import '../models/locationiq_model.dart';
|
import '../models/locationiq_model.dart';
|
||||||
import '../models/tank_model.dart';
|
import '../models/tank_model.dart';
|
||||||
import '../services/appwrite_service.dart';
|
import '../services/appwrite_service.dart';
|
||||||
@@ -62,78 +61,6 @@ class EditController extends GetxController {
|
|||||||
'${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
|
'${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _requestLocation() async {
|
|
||||||
// bool serviceEnabled;
|
|
||||||
// LocationPermission permission;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// isLoadingLocation.value = true;
|
|
||||||
|
|
||||||
// // 1. Prüfen, ob Standortdienste aktiviert sind
|
|
||||||
// serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
|
||||||
// if (!serviceEnabled) {
|
|
||||||
// return Future.error('Standortdienste sind deaktiviert.');
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 2. Berechtigungen prüfen
|
|
||||||
// permission = await Geolocator.checkPermission();
|
|
||||||
// if (permission == LocationPermission.denied) {
|
|
||||||
// permission = await Geolocator.requestPermission();
|
|
||||||
// if (permission == LocationPermission.denied) {
|
|
||||||
// return Future.error('Berechtigung verweigert.');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 3. Position abrufen
|
|
||||||
// Position position = await Geolocator.getCurrentPosition(
|
|
||||||
// locationSettings: const LocationSettings(
|
|
||||||
// accuracy: LocationAccuracy.high,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // 4. Standort über Backend-Proxy abrufen
|
|
||||||
// var lat = position.latitude;
|
|
||||||
// var lon = position.longitude;
|
|
||||||
|
|
||||||
// print('📍 Verwende Backend-Proxy für Geocoding...');
|
|
||||||
// String location = await appwriteService.geocodeLocation(lat, lon);
|
|
||||||
// locationController.text = location;
|
|
||||||
|
|
||||||
// // Info anzeigen basierend auf Ergebnis
|
|
||||||
// if (location.startsWith('Lat:')) {
|
|
||||||
// Get.snackbar(
|
|
||||||
// 'Hinweis',
|
|
||||||
// 'Adresse konnte nicht abgerufen werden. Koordinaten gespeichert.',
|
|
||||||
// snackPosition: SnackPosition.BOTTOM,
|
|
||||||
// backgroundColor: Colors.orange[100],
|
|
||||||
// colorText: Colors.orange[900],
|
|
||||||
// duration: const Duration(seconds: 3),
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// Get.snackbar(
|
|
||||||
// 'Erfolg',
|
|
||||||
// 'Standort: $location',
|
|
||||||
// snackPosition: SnackPosition.BOTTOM,
|
|
||||||
// backgroundColor: Colors.green[100],
|
|
||||||
// colorText: Colors.green[900],
|
|
||||||
// duration: const Duration(seconds: 2),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// Get.snackbar(
|
|
||||||
// "Fehler",
|
|
||||||
// "Standort konnte nicht abgerufen werden: $e",
|
|
||||||
// snackPosition: SnackPosition.BOTTOM,
|
|
||||||
// backgroundColor: Colors.red[100],
|
|
||||||
// colorText: Colors.red[900],
|
|
||||||
// );
|
|
||||||
// print("Fehler beim Abrufen des Standorts: $e");
|
|
||||||
// locationController.text = '';
|
|
||||||
// } finally {
|
|
||||||
// isLoadingLocation.value = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
Future<void> _requestLocationIQ() async {
|
Future<void> _requestLocationIQ() async {
|
||||||
bool serviceEnabled;
|
bool serviceEnabled;
|
||||||
LocationPermission permission;
|
LocationPermission permission;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter_tank_web_app/models/tank_model.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import '../models/tank_model.dart';
|
||||||
|
|
||||||
class GraphController extends GetxController {
|
class GraphController extends GetxController {
|
||||||
final listTankModel = <TankModel>[].obs;
|
final listTankModel = <TankModel>[].obs;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
//import 'dart:convert';
|
|
||||||
import 'package:appwrite/models.dart';
|
import 'package:appwrite/models.dart';
|
||||||
import 'package:appwrite/appwrite.dart';
|
import 'package:appwrite/appwrite.dart';
|
||||||
//import 'package:http/http.dart' as http;
|
|
||||||
import '../config/environment.dart';
|
import '../config/environment.dart';
|
||||||
|
|
||||||
class AppwriteService {
|
class AppwriteService {
|
||||||
@@ -167,47 +166,4 @@ class AppwriteService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Geocode coordinates using local proxy or Appwrite Function
|
|
||||||
// Future<String> geocodeLocation(double lat, double lon) async {
|
|
||||||
// // Wenn lokaler Proxy aktiviert ist, diesen verwenden
|
|
||||||
// if (Environment.useLocalProxy) {
|
|
||||||
// return _geocodeViaLocalProxy(lat, lon);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Fallback: Koordinaten zurückgeben
|
|
||||||
// return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Geocoding über lokalen Reverse Proxy
|
|
||||||
// Future<String> _geocodeViaLocalProxy(double lat, double lon) async {
|
|
||||||
// try {
|
|
||||||
// final proxyUrl = '${Environment.localProxyUrl}/?lat=$lat&lon=$lon&apiKey=${Environment.ptvApiKey}';
|
|
||||||
|
|
||||||
// print('🔄 Verwende lokalen Proxy: ${Environment.localProxyUrl}');
|
|
||||||
|
|
||||||
// final response = await http.get(Uri.parse(proxyUrl));
|
|
||||||
|
|
||||||
// if (response.statusCode == 200) {
|
|
||||||
// final data = jsonDecode(response.body);
|
|
||||||
|
|
||||||
// if (data['success'] == true) {
|
|
||||||
// final location = data['location'] as String;
|
|
||||||
// print('✅ Geocoding erfolgreich (Proxy): $location');
|
|
||||||
// return location;
|
|
||||||
// } else {
|
|
||||||
// print('❌ Geocoding fehlgeschlagen (Proxy): ${data['error']}');
|
|
||||||
// return data['fallbackLocation'] ??
|
|
||||||
// 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}';
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// print('⚠️ Proxy Response Status: ${response.statusCode}');
|
|
||||||
// return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}';
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// print('❌ Lokaler Proxy nicht erreichbar: $e');
|
|
||||||
// print('💡 Tipp: Starten Sie den Proxy mit: cd proxy-server && node server.js');
|
|
||||||
// return 'Lat: ${lat.toStringAsFixed(6)}, Lon: ${lon.toStringAsFixed(6)}';
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,16 @@
|
|||||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import '../config/environment.dart';
|
import '../config/environment.dart';
|
||||||
import '../models/locationiq_model.dart';
|
import '../models/locationiq_model.dart';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
class LocationIQService {
|
class LocationIQService {
|
||||||
static final String baseUrl = Environment.locationIQBaseUrl;
|
static final String baseUrl = Environment.locationIQBaseUrl;
|
||||||
late LocationIQ locationIQ;
|
late LocationIQ locationIQ;
|
||||||
|
|
||||||
Future<void> fetchLocationIQ(double lat, double lon) async {
|
Future<void> fetchLocationIQ(double lat, double lon) async {
|
||||||
// Hier würde die eigentliche API-Anfrage an LocationIQ erfolgen
|
|
||||||
// Zum Beispiel mit http.get() und der URL aus Environment.locationIQUrl
|
|
||||||
// Die Antwort würde dann in das LocationIQ-Modell umgewandelt werden
|
|
||||||
// https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&lat=47.93875449671056&lon=13.762706553431048&format=json
|
// https://eu1.locationiq.com/v1/reverse?key=$locationIQKey&lat=47.93875449671056&lon=13.762706553431048&format=json
|
||||||
// locationIQ = LocationIQ.fromJson(responseData);
|
|
||||||
// Simulierte Antwort (für Testzwecke)
|
// Simulierte Antwort (für Testzwecke)
|
||||||
locationIQ = LocationIQ(
|
locationIQ = LocationIQ(
|
||||||
placeId: '12345',
|
placeId: '12345',
|
||||||
|
|||||||
35
nginx.conf
35
nginx.conf
@@ -1,35 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name localhost;
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html;
|
|
||||||
|
|
||||||
# Compression
|
|
||||||
gzip on;
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_min_length 1024;
|
|
||||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
|
|
||||||
|
|
||||||
# Security headers
|
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
||||||
add_header X-Content-Type-Options "nosniff" always;
|
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
|
||||||
|
|
||||||
# Cache static assets
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
||||||
expires 1y;
|
|
||||||
add_header Cache-Control "public, immutable";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Flutter web routing
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ /index.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Health check endpoint
|
|
||||||
location /health {
|
|
||||||
access_log off;
|
|
||||||
return 200 "healthy\n";
|
|
||||||
add_header Content-Type text/plain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Dockerfile für Node.js Proxy Server
|
|
||||||
FROM node:18-alpine
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install dependencies (omit dev; no lockfile required)
|
|
||||||
RUN npm install --omit=dev
|
|
||||||
|
|
||||||
# Copy application code
|
|
||||||
COPY server.js ./
|
|
||||||
|
|
||||||
# Expose port
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
||||||
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
|
|
||||||
|
|
||||||
# Run as non-root user
|
|
||||||
USER node
|
|
||||||
|
|
||||||
# Start server
|
|
||||||
CMD ["node", "server.js"]
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
# Lokaler Reverse Proxy Server
|
|
||||||
|
|
||||||
Dieser Proxy-Server umgeht CORS-Probleme während der Entwicklung, indem er Anfragen an die PTV Geocoding API weiterleitet.
|
|
||||||
|
|
||||||
## 🚀 Installation & Start
|
|
||||||
|
|
||||||
### 1. Dependencies installieren (nur Node.js Standard-Module, keine Installation nötig)
|
|
||||||
|
|
||||||
Der Server verwendet nur Node.js Built-in Module (`http`, `https`, `url`), daher ist kein `npm install` erforderlich.
|
|
||||||
|
|
||||||
### 2. Server starten
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd proxy-server
|
|
||||||
node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
Oder mit npm:
|
|
||||||
```bash
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
Der Server läuft dann auf `http://localhost:3000`
|
|
||||||
|
|
||||||
## 📡 API Verwendung
|
|
||||||
|
|
||||||
**Endpoint:**
|
|
||||||
```
|
|
||||||
GET http://localhost:3000/?lat={latitude}&lon={longitude}&apiKey={ptv_api_key}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Beispiel:**
|
|
||||||
```
|
|
||||||
http://localhost:3000/?lat=47.9385165&lon=13.762887&apiKey=YOUR_API_KEY
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response (Erfolg):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"location": "Hauptstraße 123, 5020 Salzburg",
|
|
||||||
"coordinates": {
|
|
||||||
"lat": 47.9385165,
|
|
||||||
"lon": 13.762887
|
|
||||||
},
|
|
||||||
"rawData": { ... }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response (Fehler):**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"error": "Error message",
|
|
||||||
"fallbackLocation": "Lat: 47.938517, Lon: 13.762887"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 In Flutter App verwenden
|
|
||||||
|
|
||||||
Der Flutter Code wurde bereits angepasst, um den lokalen Proxy zu verwenden.
|
|
||||||
|
|
||||||
1. Starten Sie den Proxy-Server:
|
|
||||||
```bash
|
|
||||||
cd proxy-server
|
|
||||||
node server.js
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Starten Sie die Flutter App:
|
|
||||||
```bash
|
|
||||||
flutter run -d chrome
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Die App verwendet automatisch `http://localhost:3000` wenn verfügbar.
|
|
||||||
|
|
||||||
## ⚠️ Wichtige Hinweise
|
|
||||||
|
|
||||||
- **Nur für Entwicklung!** Dieser Server ist nicht für Produktionsumgebungen geeignet.
|
|
||||||
- Der Server muss laufen, während Sie die Flutter App im Development-Modus verwenden.
|
|
||||||
- Für Produktion: Verwenden Sie die Appwrite Function (siehe [DEPLOYMENT.md](../DEPLOYMENT.md))
|
|
||||||
|
|
||||||
## 🛑 Server stoppen
|
|
||||||
|
|
||||||
Drücken Sie `Strg+C` im Terminal, wo der Server läuft.
|
|
||||||
|
|
||||||
## 🐛 Troubleshooting
|
|
||||||
|
|
||||||
### Port bereits belegt
|
|
||||||
**Problem:** `Error: listen EADDRINUSE: address already in use :::3000`
|
|
||||||
|
|
||||||
**Lösung:**
|
|
||||||
1. Anderen Port verwenden: Ändern Sie `PORT = 3000` in `server.js`
|
|
||||||
2. Oder den bestehenden Prozess beenden:
|
|
||||||
```bash
|
|
||||||
# Port finden
|
|
||||||
lsof -i :3000
|
|
||||||
# Prozess beenden
|
|
||||||
kill -9 PID
|
|
||||||
```
|
|
||||||
|
|
||||||
### Flutter App findet Proxy nicht
|
|
||||||
**Problem:** "Failed to fetch" oder Connection Error
|
|
||||||
|
|
||||||
**Lösung:**
|
|
||||||
1. Prüfen Sie ob der Proxy läuft (`http://localhost:3000` im Browser öffnen)
|
|
||||||
2. Stellen Sie sicher, dass Port 3000 korrekt ist
|
|
||||||
3. Prüfen Sie die Browser Console für Fehler
|
|
||||||
|
|
||||||
### CORS immer noch ein Problem
|
|
||||||
**Problem:** CORS-Fehler trotz Proxy
|
|
||||||
|
|
||||||
**Lösung:**
|
|
||||||
1. Stellen Sie sicher, dass die Flutter App `localhost:3000` verwendet
|
|
||||||
2. Browser-Cache leeren
|
|
||||||
3. Entwickler-Tools → Network → "Disable cache" aktivieren
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ptv-proxy-server",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Local reverse proxy for PTV Geocoding API to bypass CORS",
|
|
||||||
"main": "server.js",
|
|
||||||
"scripts": {
|
|
||||||
"start": "node server.js",
|
|
||||||
"dev": "node server.js"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"proxy",
|
|
||||||
"cors",
|
|
||||||
"ptv",
|
|
||||||
"geocoding"
|
|
||||||
],
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
/**
|
|
||||||
* Lokaler Reverse Proxy für PTV Geocoding API
|
|
||||||
* Umgeht CORS-Probleme bei der Entwicklung
|
|
||||||
*/
|
|
||||||
|
|
||||||
const http = require('http');
|
|
||||||
const https = require('https');
|
|
||||||
const url = require('url');
|
|
||||||
|
|
||||||
const PORT = 3000;
|
|
||||||
const PTV_API_BASE = 'https://api.myptv.com';
|
|
||||||
|
|
||||||
// CORS Headers für alle Responses
|
|
||||||
const corsHeaders = {
|
|
||||||
'Access-Control-Allow-Origin': '*',
|
|
||||||
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
||||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = http.createServer((req, res) => {
|
|
||||||
console.log(`📨 ${req.method} ${req.url}`);
|
|
||||||
|
|
||||||
// Health check endpoint
|
|
||||||
if (req.url === '/health') {
|
|
||||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
||||||
res.end('healthy');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle preflight requests
|
|
||||||
if (req.method === 'OPTIONS') {
|
|
||||||
res.writeHead(200, corsHeaders);
|
|
||||||
res.end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nur GET Requests erlauben
|
|
||||||
if (req.method !== 'GET') {
|
|
||||||
res.writeHead(405, corsHeaders);
|
|
||||||
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse URL
|
|
||||||
const parsedUrl = url.parse(req.url, true);
|
|
||||||
const { lat, lon, apiKey } = parsedUrl.query;
|
|
||||||
|
|
||||||
// Validierung
|
|
||||||
if (!lat || !lon || !apiKey) {
|
|
||||||
res.writeHead(400, corsHeaders);
|
|
||||||
res.end(JSON.stringify({
|
|
||||||
error: 'Missing parameters: lat, lon, apiKey are required',
|
|
||||||
}));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PTV API URL erstellen
|
|
||||||
const ptvUrl = `${PTV_API_BASE}/geocoding/v1/locations/by-position/${lat}/${lon}?language=de&apiKey=${apiKey}`;
|
|
||||||
|
|
||||||
console.log(`🔄 Weiterleitung an: ${ptvUrl.replace(apiKey, 'API_KEY_HIDDEN')}`);
|
|
||||||
|
|
||||||
// Request an PTV API
|
|
||||||
https.get(ptvUrl, (ptvRes) => {
|
|
||||||
let data = '';
|
|
||||||
|
|
||||||
ptvRes.on('data', (chunk) => {
|
|
||||||
data += chunk;
|
|
||||||
});
|
|
||||||
|
|
||||||
ptvRes.on('end', () => {
|
|
||||||
try {
|
|
||||||
const jsonData = JSON.parse(data);
|
|
||||||
|
|
||||||
// Erfolgreiche Response
|
|
||||||
if (ptvRes.statusCode === 200) {
|
|
||||||
console.log('✅ PTV API Response erfolgreich');
|
|
||||||
|
|
||||||
// Adresse extrahieren
|
|
||||||
if (jsonData.locations && jsonData.locations.length > 0) {
|
|
||||||
const location = jsonData.locations[0];
|
|
||||||
if (location.address) {
|
|
||||||
const address = location.address;
|
|
||||||
const street = address.street || '';
|
|
||||||
const houseNumber = address.houseNumber || '';
|
|
||||||
const postalCode = address.postalCode || '';
|
|
||||||
const city = address.city || '';
|
|
||||||
|
|
||||||
const formattedAddress = `${street} ${houseNumber}, ${postalCode} ${city}`.trim();
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
success: true,
|
|
||||||
location: formattedAddress,
|
|
||||||
coordinates: {
|
|
||||||
lat: parseFloat(lat),
|
|
||||||
lon: parseFloat(lon),
|
|
||||||
},
|
|
||||||
rawData: location,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(`📍 Adresse: ${formattedAddress}`);
|
|
||||||
res.writeHead(200, corsHeaders);
|
|
||||||
res.end(JSON.stringify(response));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback auf Koordinaten
|
|
||||||
const response = {
|
|
||||||
success: true,
|
|
||||||
location: `Lat: ${parseFloat(lat).toFixed(6)}, Lon: ${parseFloat(lon).toFixed(6)}`,
|
|
||||||
coordinates: {
|
|
||||||
lat: parseFloat(lat),
|
|
||||||
lon: parseFloat(lon),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
res.writeHead(200, corsHeaders);
|
|
||||||
res.end(JSON.stringify(response));
|
|
||||||
} else {
|
|
||||||
// Fehler von PTV API
|
|
||||||
console.log(`❌ PTV API Fehler: ${ptvRes.statusCode}`);
|
|
||||||
res.writeHead(ptvRes.statusCode, corsHeaders);
|
|
||||||
res.end(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
error: `PTV API Error: ${ptvRes.statusCode}`,
|
|
||||||
fallbackLocation: `Lat: ${parseFloat(lat).toFixed(6)}, Lon: ${parseFloat(lon).toFixed(6)}`,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('❌ JSON Parse Fehler:', error.message);
|
|
||||||
res.writeHead(500, corsHeaders);
|
|
||||||
res.end(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
error: 'Failed to parse PTV API response',
|
|
||||||
fallbackLocation: `Lat: ${parseFloat(lat).toFixed(6)}, Lon: ${parseFloat(lon).toFixed(6)}`,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).on('error', (error) => {
|
|
||||||
console.error('❌ Request Fehler:', error.message);
|
|
||||||
res.writeHead(500, corsHeaders);
|
|
||||||
res.end(JSON.stringify({
|
|
||||||
success: false,
|
|
||||||
error: error.message,
|
|
||||||
fallbackLocation: `Lat: ${parseFloat(lat).toFixed(6)}, Lon: ${parseFloat(lon).toFixed(6)}`,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
|
||||||
console.log('═══════════════════════════════════════════════════════');
|
|
||||||
console.log('🚀 Lokaler Reverse Proxy Server gestartet!');
|
|
||||||
console.log(`📡 Läuft auf: http://localhost:${PORT}`);
|
|
||||||
console.log('');
|
|
||||||
console.log('📌 Verwendung:');
|
|
||||||
console.log(` http://localhost:${PORT}/?lat=47.9385&lon=13.7629&apiKey=YOUR_KEY`);
|
|
||||||
console.log('');
|
|
||||||
console.log('⚠️ Hinweis: Nur für Entwicklung verwenden!');
|
|
||||||
console.log(' Für Produktion: Appwrite Function deployen');
|
|
||||||
console.log('═══════════════════════════════════════════════════════');
|
|
||||||
console.log('');
|
|
||||||
console.log('💡 Zum Beenden: Strg+C drücken');
|
|
||||||
console.log('');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Graceful shutdown
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
console.log('\n\n👋 Server wird beendet...');
|
|
||||||
server.close(() => {
|
|
||||||
console.log('✅ Server erfolgreich gestoppt');
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Farben für Output
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
|
||||||
echo -e "${BLUE} Flutter Tank App - Lokaler Proxy Starter${NC}"
|
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Proxy Server starten
|
|
||||||
echo -e "${YELLOW}🚀 Starte lokalen Reverse Proxy Server...${NC}"
|
|
||||||
cd "$(dirname "$0")/proxy-server"
|
|
||||||
|
|
||||||
if [ ! -f "server.js" ]; then
|
|
||||||
echo -e "${YELLOW}❌ server.js nicht gefunden!${NC}"
|
|
||||||
echo -e "${YELLOW}Bitte führen Sie dieses Script aus dem Projekt-Root-Verzeichnis aus.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✅ Proxy Server wird gestartet auf http://localhost:3000${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}📌 Nächste Schritte:${NC}"
|
|
||||||
echo -e " 1. In neuem Terminal: ${GREEN}flutter run -d chrome${NC}"
|
|
||||||
echo -e " 2. Neuen Tankeintrag erstellen"
|
|
||||||
echo -e " 3. Standort wird automatisch über Proxy abgerufen"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}⚠️ Zum Beenden: Strg+C drücken${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
node server.js
|
|
||||||
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"3452d735bd38224ef2db85ca763d862d6326b1
|
|||||||
|
|
||||||
_flutter.loader.load({
|
_flutter.loader.load({
|
||||||
serviceWorkerSettings: {
|
serviceWorkerSettings: {
|
||||||
serviceWorkerVersion: "138245282" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
serviceWorkerVersion: "38490492" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user